mirror of
https://github.com/nabbar/golib.git
synced 2025-09-26 20:01:15 +08:00
Rework Archive
Package Archive: - complete rework of package - split package between compression (stream compression only) and archive (catalogue/dictionary/tape archive type) - rework compression to be stream only working without any temporary file or any like - rework archive like TAR, ZIP... to expose stream instead of writing directly file/path - rework archive like TAR, ZIP... to allow adding file from stream only and allowing to parsing local path to add it into archive - rework detection of compression / archive - rework extractAll function to not using useless local temporary file - adding test can be used as example and perform testing of most of package code - using const custom type for compression and archive allow them to be parsed, marshalled or unmarshalled from text or json and more - apply following change into other module that use it
This commit is contained in:
@@ -1,226 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
libbz2 "github.com/nabbar/golib/archive/bz2"
|
||||
libgzp "github.com/nabbar/golib/archive/gzip"
|
||||
libtar "github.com/nabbar/golib/archive/tar"
|
||||
libzip "github.com/nabbar/golib/archive/zip"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
libfpg "github.com/nabbar/golib/file/progress"
|
||||
)
|
||||
|
||||
type ArchiveType uint8
|
||||
|
||||
const (
|
||||
permDir = os.FileMode(0775)
|
||||
permFile = os.FileMode(0664)
|
||||
)
|
||||
|
||||
const (
|
||||
TypeTar = iota + 1
|
||||
TypeTarGzip
|
||||
TypeGzip
|
||||
TypeZip
|
||||
)
|
||||
|
||||
func ExtractFile(src, dst libfpg.Progress, fileNameContain, fileNameRegex string) liberr.Error {
|
||||
var (
|
||||
e error
|
||||
|
||||
tmp libfpg.Progress
|
||||
err liberr.Error
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if tmp != nil {
|
||||
_ = tmp.CloseDelete()
|
||||
}
|
||||
}()
|
||||
|
||||
if tmp, e = libfpg.Temp(""); e != nil {
|
||||
return ErrorFileOpen.Error(e)
|
||||
} else {
|
||||
dst.SetRegisterProgress(tmp)
|
||||
}
|
||||
|
||||
if _, e = src.Seek(0, io.SeekStart); e != nil {
|
||||
return ErrorFileSeek.Error(e)
|
||||
// #nosec
|
||||
}
|
||||
|
||||
if err = libbz2.GetFile(src, tmp); err == nil {
|
||||
//logger.DebugLevel.Log("try another archive...")
|
||||
return ExtractFile(tmp, dst, fileNameContain, fileNameRegex)
|
||||
} else if err.IsCode(libbz2.ErrorIOCopy) {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = libgzp.GetFile(src, tmp); err == nil {
|
||||
//logger.DebugLevel.Log("try another archive...")
|
||||
return ExtractFile(tmp, dst, fileNameContain, fileNameRegex)
|
||||
} else if !err.IsCode(libgzp.ErrorGZReader) {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = libtar.GetFile(src, tmp, fileNameContain, fileNameRegex); err == nil {
|
||||
//logger.DebugLevel.Log("try another archive...")
|
||||
return ExtractFile(tmp, dst, fileNameContain, fileNameRegex)
|
||||
} else if !err.IsCode(libtar.ErrorTarNext) {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = libzip.GetFile(src, tmp, fileNameContain, fileNameRegex); err == nil {
|
||||
//logger.DebugLevel.Log("try another archive...")
|
||||
return ExtractFile(tmp, dst, fileNameContain, fileNameRegex)
|
||||
} else if !err.IsCode(libzip.ErrorZipOpen) {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, e = dst.ReadFrom(src); e != nil {
|
||||
//logger.ErrorLevel.LogErrorCtx(logger.DebugLevel, "reopening file", err)
|
||||
return ErrorIOCopy.Error(e)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ExtractAll(src libfpg.Progress, originalName, outputPath string, defaultDirPerm os.FileMode) liberr.Error {
|
||||
var (
|
||||
e error
|
||||
i os.FileInfo
|
||||
|
||||
tmp libfpg.Progress
|
||||
dst libfpg.Progress
|
||||
err liberr.Error
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if src != nil {
|
||||
_ = src.Close()
|
||||
}
|
||||
if dst != nil {
|
||||
_ = dst.Close()
|
||||
}
|
||||
if tmp != nil {
|
||||
_ = tmp.CloseDelete()
|
||||
}
|
||||
}()
|
||||
|
||||
if tmp, e = libfpg.Temp(""); e != nil {
|
||||
return ErrorFileOpen.Error(e)
|
||||
} else {
|
||||
src.SetRegisterProgress(tmp)
|
||||
}
|
||||
|
||||
if err = libbz2.GetFile(src, tmp); err == nil {
|
||||
if inf, er := tmp.Stat(); er == nil {
|
||||
tmp.Reset(inf.Size())
|
||||
}
|
||||
return ExtractAll(tmp, originalName, outputPath, defaultDirPerm)
|
||||
} else if !err.IsCode(libbz2.ErrorIOCopy) {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = libgzp.GetFile(src, tmp); err == nil {
|
||||
if inf, er := tmp.Stat(); er == nil {
|
||||
tmp.Reset(inf.Size())
|
||||
}
|
||||
return ExtractAll(tmp, originalName, outputPath, defaultDirPerm)
|
||||
} else if !err.IsCode(libgzp.ErrorGZReader) {
|
||||
return err
|
||||
}
|
||||
|
||||
if tmp != nil {
|
||||
_ = tmp.CloseDelete()
|
||||
}
|
||||
|
||||
if i, e = os.Stat(outputPath); e != nil && os.IsNotExist(e) {
|
||||
//nolint #nosec
|
||||
/* #nosec */
|
||||
if e = os.MkdirAll(outputPath, permDir); e != nil {
|
||||
return ErrorDirCreate.Error(e)
|
||||
}
|
||||
} else if e != nil {
|
||||
return ErrorDirStat.Error(e)
|
||||
} else if !i.IsDir() {
|
||||
return ErrorDirNotDir.Error(nil)
|
||||
}
|
||||
|
||||
if err = libtar.GetAll(src, outputPath, defaultDirPerm); err == nil {
|
||||
return nil
|
||||
} else if !err.IsCode(libtar.ErrorTarNext) {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = libzip.GetAll(src, outputPath, defaultDirPerm); err == nil {
|
||||
return nil
|
||||
} else if !err.IsCode(libzip.ErrorZipOpen) {
|
||||
return err
|
||||
}
|
||||
|
||||
if dst, e = libfpg.New(filepath.Join(outputPath, originalName), os.O_RDWR|os.O_CREATE|os.O_TRUNC, permFile); e != nil {
|
||||
return ErrorFileOpen.Error(e)
|
||||
} else {
|
||||
src.SetRegisterProgress(dst)
|
||||
}
|
||||
|
||||
if _, e = src.Seek(0, io.SeekStart); e != nil {
|
||||
return ErrorFileSeek.Error(e)
|
||||
} else if _, e = dst.ReadFrom(src); e != nil {
|
||||
return ErrorIOCopy.Error(e)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateArchive(archiveType ArchiveType, archive libfpg.Progress, stripPath string, comment string, pathContent ...string) (created bool, err liberr.Error) {
|
||||
if len(pathContent) < 1 {
|
||||
//nolint #goerr113
|
||||
return false, ErrorParamEmpty.Error(fmt.Errorf("pathContent is empty"))
|
||||
}
|
||||
|
||||
switch archiveType {
|
||||
case TypeGzip:
|
||||
return libgzp.Create(archive, stripPath, comment, pathContent...)
|
||||
case TypeTar:
|
||||
return libtar.Create(archive, stripPath, comment, pathContent...)
|
||||
case TypeTarGzip:
|
||||
return libtar.CreateGzip(archive, stripPath, comment, pathContent...)
|
||||
case TypeZip:
|
||||
return libzip.Create(archive, stripPath, comment, pathContent...)
|
||||
|
||||
//@TODO: add zip mode
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
@@ -23,77 +23,53 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package gzip
|
||||
package archive
|
||||
|
||||
import (
|
||||
gz "compress/gzip"
|
||||
"io"
|
||||
|
||||
"github.com/nabbar/golib/errors"
|
||||
libfpg "github.com/nabbar/golib/file/progress"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetFile(src io.ReadSeeker, dst io.WriteSeeker) errors.Error {
|
||||
if _, e := src.Seek(0, io.SeekStart); e != nil {
|
||||
return ErrorFileSeek.Error(e)
|
||||
} else if _, e = dst.Seek(0, io.SeekStart); e != nil {
|
||||
return ErrorFileSeek.Error(e)
|
||||
func (a Algorithm) MarshalText() ([]byte, error) {
|
||||
return []byte(a.String()), nil
|
||||
}
|
||||
|
||||
func (a *Algorithm) UnmarshalText(b []byte) error {
|
||||
*a = None
|
||||
|
||||
s := strings.Trim(string(b), "\"")
|
||||
s = strings.Trim(s, "'")
|
||||
s = strings.TrimSpace(s)
|
||||
|
||||
switch {
|
||||
case strings.EqualFold(s, Tar.String()):
|
||||
*a = Tar
|
||||
case strings.EqualFold(s, Zip.String()):
|
||||
*a = Zip
|
||||
default:
|
||||
*a = None
|
||||
}
|
||||
|
||||
r, e := gz.NewReader(src)
|
||||
if e != nil {
|
||||
return ErrorGZReader.Error(e)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a Algorithm) MarshalJSON() ([]byte, error) {
|
||||
if a.IsNone() {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return append(append([]byte{'"'}, []byte(a.String())...), '"'), nil
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = r.Close()
|
||||
}()
|
||||
func (a *Algorithm) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
// #nosec
|
||||
_, e = io.Copy(dst, r)
|
||||
|
||||
if e != nil {
|
||||
return ErrorIOCopy.Error(e)
|
||||
} else if _, e = dst.Seek(0, io.SeekStart); e != nil {
|
||||
return ErrorFileSeek.Error(e)
|
||||
} else {
|
||||
if n := []byte("null"); bytes.Equal(b, n) {
|
||||
*a = None
|
||||
return nil
|
||||
} else if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return a.UnmarshalText([]byte(s))
|
||||
}
|
||||
}
|
||||
|
||||
func GetGunZipSize(src io.ReadSeeker) int64 {
|
||||
if _, e := src.Seek(0, io.SeekStart); e != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
r, e := gz.NewReader(src)
|
||||
if e != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = r.Close()
|
||||
}()
|
||||
|
||||
if s, k := src.(libfpg.Progress); k {
|
||||
s.RegisterFctReset(func(size, current int64) {
|
||||
|
||||
})
|
||||
s.RegisterFctIncrement(func(size int64) {
|
||||
|
||||
})
|
||||
s.RegisterFctEOF(func() {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
var n int64
|
||||
// #nosec
|
||||
n, e = io.Copy(io.Discard, r)
|
||||
|
||||
if e != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
94
archive/archive/interface.go
Normal file
94
archive/archive/interface.go
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
|
||||
arctps "github.com/nabbar/golib/archive/archive/types"
|
||||
)
|
||||
|
||||
func Parse(s string) Algorithm {
|
||||
var alg = None
|
||||
if e := alg.UnmarshalText([]byte(s)); e != nil {
|
||||
return None
|
||||
} else {
|
||||
return alg
|
||||
}
|
||||
}
|
||||
|
||||
// Detect will try to detect the algorithm of the input and returns the corresponding reader.
|
||||
// This function will read the first 6 bytes of the input and try to detect the algorithm.
|
||||
// If algorithm detection trigger a supported algorithm, the function will try to convert
|
||||
// the input to appropriate reader for the archive.
|
||||
// In any case, if en error occurs, the function will return an error.
|
||||
// Otherwise, the function will return the algorithm, the reader and a nil error.
|
||||
//
|
||||
// If the input is a zip archive and the input is not a io.ReaderAt compatible, the function will return.
|
||||
// If the input is a tar archive and the input is a strict io.ReadCloser, with no seek or read at compatible,
|
||||
// the reader result could be use only for one time.
|
||||
//
|
||||
// This difference are based on how the algorithm work:
|
||||
// - zip: will use dictionary / catalog to store position and metadata of each embedded file
|
||||
// - tar: (TAR = Tape ARchive) will store each file continuously beginning with his metadata and following with his content.
|
||||
//
|
||||
// As that, a strict reader could be use only for tar archive and the reader result could be use only for one time.
|
||||
// In this case, the best use if calling the walk function of the reader.
|
||||
func Detect(r io.ReadCloser) (Algorithm, arctps.Reader, io.ReadCloser, error) {
|
||||
var (
|
||||
err error
|
||||
buf []byte
|
||||
bfr = &rdr{
|
||||
r: r,
|
||||
b: bufio.NewReader(r),
|
||||
}
|
||||
)
|
||||
|
||||
if buf, err = bfr.Peek(265); err != nil {
|
||||
return None, nil, nil, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case Tar.DetectHeader(buf): // tar
|
||||
if t, e := Tar.Reader(bfr); e != nil {
|
||||
return None, nil, nil, e
|
||||
} else {
|
||||
return Tar, t, bfr, nil
|
||||
}
|
||||
|
||||
case Zip.DetectHeader(buf): // zip
|
||||
bfr.b = nil // do not use buffer (using ReaderAt)
|
||||
if z, e := Zip.Reader(bfr); e != nil {
|
||||
return None, nil, nil, e
|
||||
} else {
|
||||
return Zip, z, r, nil
|
||||
}
|
||||
|
||||
default:
|
||||
return None, nil, bfr, nil
|
||||
}
|
||||
}
|
61
archive/archive/io.go
Normal file
61
archive/archive/io.go
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
arctar "github.com/nabbar/golib/archive/archive/tar"
|
||||
arctps "github.com/nabbar/golib/archive/archive/types"
|
||||
arczip "github.com/nabbar/golib/archive/archive/zip"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidAlgorithm = errors.New("invalid algorithm")
|
||||
)
|
||||
|
||||
func (a Algorithm) Reader(r io.ReadCloser) (arctps.Reader, error) {
|
||||
switch a {
|
||||
case Tar:
|
||||
return arctar.NewReader(r)
|
||||
case Zip:
|
||||
return arczip.NewReader(r)
|
||||
default:
|
||||
return nil, ErrInvalidAlgorithm
|
||||
}
|
||||
}
|
||||
|
||||
func (a Algorithm) Writer(w io.WriteCloser) (arctps.Writer, error) {
|
||||
switch a {
|
||||
case Tar:
|
||||
return arctar.NewWriter(w)
|
||||
case Zip:
|
||||
return arczip.NewWriter(w)
|
||||
default:
|
||||
return nil, ErrInvalidAlgorithm
|
||||
}
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
MinPkgArchive = liberr.MinPkgArchive
|
||||
MinPkgArchiveBZ2 = MinPkgArchive + 20
|
||||
MinPkgArchiveGZip = MinPkgArchiveBZ2 + 20
|
||||
MinPkgArchiveTar = MinPkgArchiveGZip + 20
|
||||
MinPkgArchiveZip = MinPkgArchiveTar + 20
|
||||
)
|
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
pathSeparatorOs = string(os.PathSeparator)
|
||||
pathSeparatorCommon = "/"
|
||||
pathParentCommon = ".."
|
||||
)
|
||||
|
||||
type File struct {
|
||||
Name string
|
||||
Path string
|
||||
}
|
||||
|
||||
func (a File) Matching(containt string) bool {
|
||||
if len(containt) < 1 {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(strings.ToLower(a.Name), strings.ToLower(containt))
|
||||
}
|
||||
|
||||
func (a File) Regex(regex string) bool {
|
||||
if len(regex) < 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
b, _ := regexp.MatchString(regex, a.Name)
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func (a File) MatchingFullPath(containt string) bool {
|
||||
if len(containt) < 1 {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(strings.ToLower(a.GetKeyMap()), strings.ToLower(containt))
|
||||
}
|
||||
|
||||
func (a File) RegexFullPath(regex string) bool {
|
||||
if len(regex) < 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
b, _ := regexp.MatchString(regex, a.GetKeyMap())
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func (a File) GetKeyMap() string {
|
||||
return filepath.Join(a.Path, a.Name)
|
||||
}
|
||||
|
||||
func (a File) GetDestFileOnly(baseDestination string) string {
|
||||
return filepath.Join(baseDestination, a.Name)
|
||||
}
|
||||
|
||||
func (a File) GetDestWithPath(baseDestination string) string {
|
||||
return filepath.Join(baseDestination, a.Path, a.Name)
|
||||
}
|
||||
|
||||
func NewFile(name, path string) File {
|
||||
return File{
|
||||
Name: name,
|
||||
Path: path,
|
||||
}
|
||||
}
|
||||
|
||||
func NewFileFullPath(fullpath string) File {
|
||||
return NewFile(filepath.Base(fullpath), filepath.Dir(fullpath))
|
||||
}
|
||||
|
||||
func CleanPath(p string) string {
|
||||
for {
|
||||
if strings.HasPrefix(p, pathParentCommon) {
|
||||
p = strings.TrimPrefix(p, pathParentCommon)
|
||||
} else if strings.HasPrefix(p, pathSeparatorCommon+pathParentCommon) {
|
||||
p = strings.TrimPrefix(p, pathSeparatorCommon+pathParentCommon)
|
||||
} else if strings.HasPrefix(p, pathSeparatorOs+pathParentCommon) {
|
||||
p = strings.TrimPrefix(p, pathSeparatorOs+pathParentCommon)
|
||||
} else {
|
||||
return filepath.Clean(p)
|
||||
}
|
||||
}
|
||||
}
|
165
archive/archive/reader.go
Normal file
165
archive/archive/reader.go
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"io/fs"
|
||||
)
|
||||
|
||||
// struct to allow compatibility with io.ReadSeeker for all type of archive
|
||||
type rdr struct {
|
||||
r io.ReadCloser
|
||||
b *bufio.Reader
|
||||
}
|
||||
|
||||
func (o *rdr) Close() error {
|
||||
return o.r.Close()
|
||||
}
|
||||
|
||||
func (o *rdr) Read(p []byte) (n int, err error) {
|
||||
if o.b != nil {
|
||||
return o.b.Read(p)
|
||||
}
|
||||
|
||||
return o.r.Read(p)
|
||||
}
|
||||
|
||||
func (o *rdr) Peek(n int) ([]byte, error) {
|
||||
if o.b != nil {
|
||||
return o.b.Peek(n)
|
||||
} else {
|
||||
b := bufio.NewReader(o.r)
|
||||
return b.Peek(n)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *rdr) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
if r, k := o.r.(io.ReaderAt); k {
|
||||
return r.ReadAt(p, off)
|
||||
}
|
||||
|
||||
if r, k := o.r.(io.ReadSeeker); k {
|
||||
if _, err = r.Seek(off, io.SeekStart); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if o.b != nil {
|
||||
o.b.Reset(r)
|
||||
return o.b.Read(p)
|
||||
} else {
|
||||
return o.r.Read(p)
|
||||
}
|
||||
}
|
||||
|
||||
return 0, fs.ErrInvalid
|
||||
}
|
||||
|
||||
func (o *rdr) Size() int64 {
|
||||
var s int64
|
||||
|
||||
if r, k := o.r.(io.Seeker); k {
|
||||
if c, e := r.Seek(0, io.SeekCurrent); e != nil {
|
||||
return 0
|
||||
} else if _, e = r.Seek(c, io.SeekStart); e != nil {
|
||||
return 0
|
||||
} else if s, e = r.Seek(0, io.SeekEnd); e != nil {
|
||||
return 0
|
||||
} else if _, e = r.Seek(c, io.SeekStart); e != nil {
|
||||
return 0
|
||||
} else {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
if r, k := o.r.(io.ReaderAt); k {
|
||||
if _, e := r.ReadAt(nil, 0); e != nil {
|
||||
return 0
|
||||
} else if s, e = io.Copy(io.Discard, o.r); e != nil {
|
||||
return 0
|
||||
} else if _, e = r.ReadAt(nil, s); e != nil {
|
||||
return 0
|
||||
} else if o.b != nil {
|
||||
o.b.Reset(o.r)
|
||||
return s
|
||||
} else {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (o *rdr) Seek(offset int64, whence int) (int64, error) {
|
||||
if r, k := o.r.(io.Seeker); k {
|
||||
if n, e := r.Seek(offset, whence); e != nil {
|
||||
return n, e
|
||||
} else if o.b != nil {
|
||||
o.b.Reset(o.r)
|
||||
return n, nil
|
||||
} else {
|
||||
return n, nil
|
||||
}
|
||||
}
|
||||
|
||||
if whence != io.SeekStart {
|
||||
return 0, fs.ErrInvalid
|
||||
}
|
||||
|
||||
if _, e := o.ReadAt(make([]byte, 0), 0); e != nil {
|
||||
return 0, e
|
||||
} else if o.b != nil {
|
||||
o.b.Reset(o.r)
|
||||
return 0, nil
|
||||
} else {
|
||||
return 0, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (o *rdr) Reset() bool {
|
||||
if r, k := o.r.(io.Seeker); k {
|
||||
_, e := r.Seek(0, io.SeekStart)
|
||||
if e == nil {
|
||||
if o.b != nil {
|
||||
o.b.Reset(o.r)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if r, k := o.r.(io.ReaderAt); k {
|
||||
_, e := r.ReadAt(nil, 0)
|
||||
if e == nil {
|
||||
if o.b != nil {
|
||||
o.b.Reset(o.r)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
@@ -23,32 +23,25 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package bz2
|
||||
package tar
|
||||
|
||||
import (
|
||||
"compress/bzip2"
|
||||
"archive/tar"
|
||||
"io"
|
||||
|
||||
"github.com/nabbar/golib/errors"
|
||||
arctps "github.com/nabbar/golib/archive/archive/types"
|
||||
)
|
||||
|
||||
func GetFile(src io.ReadSeeker, dst io.WriteSeeker) errors.Error {
|
||||
if _, e := src.Seek(0, io.SeekStart); e != nil {
|
||||
return ErrorFileSeek.Error(e)
|
||||
} else if _, e = dst.Seek(0, io.SeekStart); e != nil {
|
||||
return ErrorFileSeek.Error(e)
|
||||
}
|
||||
|
||||
r := bzip2.NewReader(src)
|
||||
|
||||
// #nosec
|
||||
_, e := io.Copy(dst, r)
|
||||
|
||||
if e != nil {
|
||||
return ErrorIOCopy.Error(e)
|
||||
} else if _, e = dst.Seek(0, io.SeekStart); e != nil {
|
||||
return ErrorFileSeek.Error(e)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
func NewReader(r io.ReadCloser) (arctps.Reader, error) {
|
||||
return &rdr{
|
||||
r: r,
|
||||
z: tar.NewReader(r),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewWriter(w io.WriteCloser) (arctps.Writer, error) {
|
||||
return &wrt{
|
||||
w: w,
|
||||
z: tar.NewWriter(w),
|
||||
}, nil
|
||||
}
|
170
archive/archive/tar/reader.go
Normal file
170
archive/archive/tar/reader.go
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package tar
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"io"
|
||||
"io/fs"
|
||||
|
||||
arctps "github.com/nabbar/golib/archive/archive/types"
|
||||
)
|
||||
|
||||
type reset interface {
|
||||
Reset() bool
|
||||
}
|
||||
|
||||
type rdr struct {
|
||||
r io.ReadCloser
|
||||
z *tar.Reader
|
||||
}
|
||||
|
||||
func (o *rdr) Reset() bool {
|
||||
if r, k := o.r.(reset); k {
|
||||
return r.Reset()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (o *rdr) Close() error {
|
||||
return o.r.Close()
|
||||
}
|
||||
|
||||
func (o *rdr) List() ([]string, error) {
|
||||
var (
|
||||
e error
|
||||
h *tar.Header
|
||||
l = make([]string, 0)
|
||||
)
|
||||
|
||||
if o.Reset() {
|
||||
o.z = tar.NewReader(o.r)
|
||||
}
|
||||
|
||||
for e == nil {
|
||||
h, e = o.z.Next()
|
||||
if h != nil {
|
||||
l = append(l, h.Name)
|
||||
_, _ = io.Copy(io.Discard, o.z)
|
||||
}
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func (o *rdr) Info(s string) (fs.FileInfo, error) {
|
||||
var (
|
||||
e error
|
||||
h *tar.Header
|
||||
)
|
||||
|
||||
if o.Reset() {
|
||||
o.z = tar.NewReader(o.r)
|
||||
}
|
||||
|
||||
for e == nil {
|
||||
h, e = o.z.Next()
|
||||
if h != nil && h.Name == s {
|
||||
return h.FileInfo(), nil
|
||||
} else if h != nil {
|
||||
_, _ = io.Copy(io.Discard, o.z)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fs.ErrNotExist
|
||||
|
||||
}
|
||||
|
||||
func (o *rdr) Get(s string) (io.ReadCloser, error) {
|
||||
var (
|
||||
e error
|
||||
h *tar.Header
|
||||
)
|
||||
|
||||
if o.Reset() {
|
||||
o.z = tar.NewReader(o.r)
|
||||
}
|
||||
|
||||
for e == nil {
|
||||
h, e = o.z.Next()
|
||||
if h != nil && h.Name == s {
|
||||
return io.NopCloser(o.z), nil
|
||||
} else if h != nil {
|
||||
_, _ = io.Copy(io.Discard, o.z)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fs.ErrNotExist
|
||||
}
|
||||
|
||||
func (o *rdr) Has(s string) bool {
|
||||
var (
|
||||
e error
|
||||
h *tar.Header
|
||||
)
|
||||
|
||||
if o.Reset() {
|
||||
o.z = tar.NewReader(o.r)
|
||||
}
|
||||
|
||||
for e == nil {
|
||||
h, e = o.z.Next()
|
||||
if h != nil && h.Name == s {
|
||||
return true
|
||||
} else if h != nil {
|
||||
_, _ = io.Copy(io.Discard, o.z)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (o *rdr) Walk(fct arctps.FuncExtract) {
|
||||
var (
|
||||
e error
|
||||
h *tar.Header
|
||||
)
|
||||
|
||||
if o.Reset() {
|
||||
o.z = tar.NewReader(o.r)
|
||||
}
|
||||
|
||||
for e == nil {
|
||||
h, e = o.z.Next()
|
||||
|
||||
if h == nil || e != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if !fct(h.FileInfo(), io.NopCloser(o.z), h.Name, h.Linkname) {
|
||||
return
|
||||
}
|
||||
|
||||
// prevent file cursor not at EOF of current file
|
||||
_, _ = io.Copy(io.Discard, o.z)
|
||||
}
|
||||
}
|
157
archive/archive/tar/writer.go
Normal file
157
archive/archive/tar/writer.go
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package tar
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
arctps "github.com/nabbar/golib/archive/archive/types"
|
||||
)
|
||||
|
||||
type wrt struct {
|
||||
w io.WriteCloser
|
||||
z *tar.Writer
|
||||
}
|
||||
|
||||
func (o *wrt) Close() error {
|
||||
if e := o.z.Flush(); e != nil {
|
||||
return e
|
||||
} else if e = o.z.Close(); e != nil {
|
||||
return e
|
||||
} else if e = o.w.Close(); e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add adds a file to the tar archive.
|
||||
//
|
||||
// It takes in the file information, the file reader, and the target path if the new file is a link.
|
||||
// It returns an error if any operation fails.
|
||||
func (o *wrt) Add(i fs.FileInfo, r io.ReadCloser, forcePath, target string) error {
|
||||
var (
|
||||
e error
|
||||
h *tar.Header
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if r != nil {
|
||||
_ = r.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
if h, e = tar.FileInfoHeader(i, target); e != nil {
|
||||
return e
|
||||
} else if len(target) > 0 {
|
||||
h.Linkname = target
|
||||
}
|
||||
|
||||
if len(forcePath) > 0 {
|
||||
h.Name = forcePath
|
||||
}
|
||||
|
||||
if e = o.z.WriteHeader(h); e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
if _, e = io.Copy(o.z, r); e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *wrt) FromPath(source string, filter string, fct arctps.ReplaceName) error {
|
||||
if i, e := os.Stat(source); e == nil && !i.IsDir() {
|
||||
return o.addFiltering(source, filter, fct, i)
|
||||
}
|
||||
|
||||
return filepath.Walk(source, func(path string, info fs.FileInfo, e error) error {
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
return o.addFiltering(path, filter, fct, info)
|
||||
})
|
||||
}
|
||||
|
||||
func (o *wrt) addFiltering(source string, filter string, fct arctps.ReplaceName, info fs.FileInfo) error {
|
||||
var (
|
||||
ok bool
|
||||
err error
|
||||
hdf *os.File
|
||||
target string
|
||||
)
|
||||
|
||||
if len(filter) < 1 {
|
||||
filter = "*"
|
||||
}
|
||||
|
||||
if fct == nil {
|
||||
fct = func(source string) string {
|
||||
return source
|
||||
}
|
||||
}
|
||||
|
||||
if ok, err = filepath.Match(filter, source); err != nil {
|
||||
return err
|
||||
} else if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if info == nil {
|
||||
return fs.ErrInvalid
|
||||
} else if info.IsDir() {
|
||||
return nil
|
||||
} else if info.Mode()&os.ModeSymlink != 0 { // SymLink
|
||||
if target, err = os.Readlink(source); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if info.Mode()&os.ModeDevice != 0 { // HardLink
|
||||
if target, err = os.Readlink(source); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if info.Mode().IsRegular() {
|
||||
if hdf, err = os.Open(source); err != nil {
|
||||
return err
|
||||
} else {
|
||||
defer func() {
|
||||
_ = hdf.Close()
|
||||
}()
|
||||
}
|
||||
} else {
|
||||
return fs.ErrInvalid
|
||||
}
|
||||
|
||||
return o.Add(info, hdf, fct(source), target)
|
||||
}
|
80
archive/archive/types.go
Normal file
80
archive/archive/types.go
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive
|
||||
|
||||
import "bytes"
|
||||
|
||||
type Algorithm uint8
|
||||
|
||||
const (
|
||||
None Algorithm = iota
|
||||
Tar
|
||||
Zip
|
||||
)
|
||||
|
||||
func (a Algorithm) IsNone() bool {
|
||||
return a == None
|
||||
}
|
||||
|
||||
func (a Algorithm) String() string {
|
||||
switch a {
|
||||
case Tar:
|
||||
return "tar"
|
||||
case Zip:
|
||||
return "zip"
|
||||
default:
|
||||
return "none"
|
||||
}
|
||||
}
|
||||
|
||||
func (a Algorithm) Extension() string {
|
||||
switch a {
|
||||
case Tar:
|
||||
return ".tar"
|
||||
case Zip:
|
||||
return ".zip"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (a Algorithm) DetectHeader(h []byte) bool {
|
||||
if len(h) < 263 {
|
||||
return false
|
||||
}
|
||||
|
||||
switch a {
|
||||
case Tar:
|
||||
exp := append([]byte("ustar"), 0x00)
|
||||
val := h[257:263]
|
||||
return bytes.Equal(val, exp)
|
||||
case Zip:
|
||||
exp := []byte{0x50, 0x4b, 0x03, 0x04}
|
||||
return bytes.Equal(h[0:4], exp)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
77
archive/archive/types/reader.go
Normal file
77
archive/archive/types/reader.go
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
)
|
||||
|
||||
type FuncExtract func(fs.FileInfo, io.ReadCloser, string, string) bool
|
||||
|
||||
type Reader interface {
|
||||
io.Closer
|
||||
|
||||
// List try to return a slice of all path into the archive or an error.
|
||||
List() ([]string, error)
|
||||
// Info returns the file information as fs.FileInfo for the given path or an error.
|
||||
//
|
||||
// Parameters:
|
||||
// - string: the path of the embedded file into the archive to get information for.
|
||||
//
|
||||
// Returns:
|
||||
// - fs.FileInfo: the file information for the given path.
|
||||
// - error: an error if the file information could not be retrieved.
|
||||
Info(string) (fs.FileInfo, error)
|
||||
// Get retrieves an io.ReadCloser or an error based on the provided file path.
|
||||
//
|
||||
// Parameters:
|
||||
// - string: the path of the embedded file into the archive to get information for.
|
||||
//
|
||||
// Returns:
|
||||
// - io.ReadCloser: the read/close stream for the given path.
|
||||
// - error: an error if the file information could not be retrieved.
|
||||
Get(string) (io.ReadCloser, error)
|
||||
// Has will check if the archive contains the given path.
|
||||
//
|
||||
// Parameters:
|
||||
// - string: the path of the embedded file into the archive to get information for.
|
||||
//
|
||||
// Returns:
|
||||
// - bool: true if the archive contains the given path.
|
||||
Has(string) bool
|
||||
// Walk applies the given function to each element in the archive.
|
||||
//
|
||||
// Parameters:
|
||||
// - FuncExtract: the function will be call on each item in the archive.
|
||||
// The function can return false to stop or true to continue the walk.
|
||||
// The function will accept the following parameters:
|
||||
// - fs.FileInfo: the file information for the given path.
|
||||
// - io.ReadCloser: the read/close stream for the given path.
|
||||
// - string: the path of the embedded file into the archive.
|
||||
// - string: the link target of the embedded file if it is a link or a symlink.
|
||||
Walk(FuncExtract)
|
||||
}
|
56
archive/archive/types/writer.go
Normal file
56
archive/archive/types/writer.go
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
)
|
||||
|
||||
type ReplaceName func(string) string
|
||||
|
||||
type Writer interface {
|
||||
io.Closer
|
||||
|
||||
// Add will add the given file into the archive.
|
||||
//
|
||||
// Parameter(s):
|
||||
// - fs.FileInfo: the file information for the given path (permission, size, etc...).
|
||||
// - io.ReadCloser: the read/close stream to read the data and store it into the archive.
|
||||
// - string: use to force a different pathname for the embedded file into the archive.
|
||||
// - string: use to specify the target if the embedded file is a link.
|
||||
// Return type: error
|
||||
Add(fs.FileInfo, io.ReadCloser, string, string) error
|
||||
|
||||
// FromPath will parse recursively the given path and add it into the archive
|
||||
//
|
||||
// Parameter(s):
|
||||
// - string: the source path to parse recursively and add into the archive.
|
||||
// - string: a filtering string to accept only certain files (empty do disable filtering).
|
||||
// - ReplaceName: a function to replace the name of the embedded file, if needed.
|
||||
// Returns error if triggered
|
||||
FromPath(string, string, ReplaceName) error
|
||||
}
|
75
archive/archive/zip/interface.go
Normal file
75
archive/archive/zip/interface.go
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package zip
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"io"
|
||||
"io/fs"
|
||||
|
||||
arctps "github.com/nabbar/golib/archive/archive/types"
|
||||
)
|
||||
|
||||
type readerSize interface {
|
||||
Size() int64
|
||||
}
|
||||
|
||||
type readerSeek interface {
|
||||
io.Seeker
|
||||
}
|
||||
|
||||
type readerAt interface {
|
||||
io.ReadCloser
|
||||
io.ReaderAt
|
||||
}
|
||||
|
||||
func NewReader(r io.ReadCloser) (arctps.Reader, error) {
|
||||
if s, k := r.(readerSize); !k {
|
||||
return nil, fs.ErrInvalid
|
||||
} else if ra, ok := r.(readerAt); !ok {
|
||||
return nil, fs.ErrInvalid
|
||||
} else if rs, o := r.(io.Seeker); !o {
|
||||
return nil, fs.ErrInvalid
|
||||
} else if siz := s.Size(); siz <= 0 {
|
||||
return nil, fs.ErrInvalid
|
||||
} else if _, e := rs.Seek(0, io.SeekStart); e != nil {
|
||||
return nil, e
|
||||
} else if z, err := zip.NewReader(ra, siz); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return &rdr{
|
||||
r: r,
|
||||
z: z,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func NewWriter(w io.WriteCloser) (arctps.Writer, error) {
|
||||
return &wrt{
|
||||
w: w,
|
||||
z: zip.NewWriter(w),
|
||||
}, nil
|
||||
}
|
92
archive/archive/zip/reader.go
Normal file
92
archive/archive/zip/reader.go
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package zip
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"io"
|
||||
"io/fs"
|
||||
|
||||
arctps "github.com/nabbar/golib/archive/archive/types"
|
||||
)
|
||||
|
||||
type rdr struct {
|
||||
r io.ReadCloser
|
||||
z *zip.Reader
|
||||
}
|
||||
|
||||
func (o *rdr) Close() error {
|
||||
return o.r.Close()
|
||||
}
|
||||
|
||||
func (o *rdr) List() ([]string, error) {
|
||||
var res = make([]string, 0, len(o.z.File))
|
||||
|
||||
for _, f := range o.z.File {
|
||||
res = append(res, f.Name)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (o *rdr) Info(s string) (fs.FileInfo, error) {
|
||||
for _, f := range o.z.File {
|
||||
if f.Name == s {
|
||||
return f.FileInfo(), nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fs.ErrNotExist
|
||||
}
|
||||
|
||||
func (o *rdr) Get(s string) (io.ReadCloser, error) {
|
||||
for _, f := range o.z.File {
|
||||
if f.Name == s {
|
||||
return f.Open()
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fs.ErrNotExist
|
||||
}
|
||||
|
||||
func (o *rdr) Has(s string) bool {
|
||||
for _, f := range o.z.File {
|
||||
if f.Name == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (o *rdr) Walk(fct arctps.FuncExtract) {
|
||||
for _, f := range o.z.File {
|
||||
r, _ := f.Open()
|
||||
if !fct(f.FileInfo(), r, f.Name, "") {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
141
archive/archive/zip/writer.go
Normal file
141
archive/archive/zip/writer.go
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package zip
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
arctps "github.com/nabbar/golib/archive/archive/types"
|
||||
)
|
||||
|
||||
type wrt struct {
|
||||
w io.WriteCloser
|
||||
z *zip.Writer
|
||||
}
|
||||
|
||||
func (o *wrt) Close() error {
|
||||
if e := o.z.Flush(); e != nil {
|
||||
return e
|
||||
} else if e = o.z.Close(); e != nil {
|
||||
return e
|
||||
} else if e = o.w.Close(); e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *wrt) Add(i fs.FileInfo, r io.ReadCloser, forcePath, notUse string) error {
|
||||
var (
|
||||
e error
|
||||
h *zip.FileHeader
|
||||
w io.Writer
|
||||
)
|
||||
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if r != nil {
|
||||
_ = r.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
if h, e = zip.FileInfoHeader(i); e != nil {
|
||||
return e
|
||||
} else if len(forcePath) > 0 {
|
||||
h.Name = forcePath
|
||||
}
|
||||
|
||||
if w, e = o.z.CreateHeader(h); e != nil {
|
||||
return e
|
||||
} else if _, e = io.Copy(w, r); e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *wrt) FromPath(source string, filter string, fct arctps.ReplaceName) error {
|
||||
if i, e := os.Stat(source); e == nil && !i.IsDir() {
|
||||
return o.addFiltering(source, filter, fct, i)
|
||||
}
|
||||
|
||||
return filepath.Walk(source, func(path string, info fs.FileInfo, e error) error {
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
return o.addFiltering(path, filter, fct, info)
|
||||
})
|
||||
}
|
||||
|
||||
func (o *wrt) addFiltering(source string, filter string, fct arctps.ReplaceName, info fs.FileInfo) error {
|
||||
var (
|
||||
ok bool
|
||||
err error
|
||||
hdf *os.File
|
||||
)
|
||||
|
||||
if len(filter) < 1 {
|
||||
filter = "*"
|
||||
}
|
||||
|
||||
if fct == nil {
|
||||
fct = func(source string) string {
|
||||
return source
|
||||
}
|
||||
}
|
||||
|
||||
if ok, err = filepath.Match(filter, source); err != nil {
|
||||
return err
|
||||
} else if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if info == nil {
|
||||
return fs.ErrInvalid
|
||||
} else if info.IsDir() {
|
||||
return nil
|
||||
} else if info.Mode().IsRegular() {
|
||||
if hdf, err = os.Open(source); err != nil {
|
||||
return err
|
||||
} else {
|
||||
defer func() {
|
||||
_ = hdf.Close()
|
||||
}()
|
||||
}
|
||||
} else {
|
||||
return fs.ErrInvalid
|
||||
}
|
||||
|
||||
return o.Add(info, hdf, fct(source), "")
|
||||
}
|
118
archive/archive_bzip_test.go
Normal file
118
archive/archive_bzip_test.go
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive_test
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
libarc "github.com/nabbar/golib/archive"
|
||||
arccmp "github.com/nabbar/golib/archive/compress"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("archive/compress/bzip", func() {
|
||||
Context("Write/Read a bzip compressed file", func() {
|
||||
It("Create a bzip compressed file must succeed", func() {
|
||||
var (
|
||||
hdf *os.File
|
||||
buf *bufio.Writer
|
||||
wrt io.WriteCloser
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
arc[arccmp.Bzip2.String()] = "lorem_ipsum" + arccmp.Bzip2.Extension()
|
||||
|
||||
hdf, err = os.Create(arc[arccmp.Bzip2.String()])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hdf).ToNot(BeNil())
|
||||
|
||||
wrt, err = arccmp.Bzip2.Writer(hdf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(wrt).ToNot(BeNil())
|
||||
|
||||
buf = bufio.NewWriter(wrt)
|
||||
_, err = buf.WriteString(loremIpsum)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = buf.Flush()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Sync()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = wrt.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("Detect and Extract a bzip compressed file must succeed", func() {
|
||||
var (
|
||||
hdf *os.File
|
||||
alg arccmp.Algorithm
|
||||
rdr io.ReadCloser
|
||||
buf *bufio.Reader
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
hdf, err = os.Open(arc[arccmp.Bzip2.String()])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hdf).ToNot(BeNil())
|
||||
|
||||
alg, rdr, err = libarc.DetectCompression(hdf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rdr).ToNot(BeNil())
|
||||
Expect(alg).To(Equal(arccmp.Bzip2))
|
||||
|
||||
buf = bufio.NewReader(rdr)
|
||||
_, err = io.Copy(io.Discard, buf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = buf.UnreadByte()
|
||||
Expect(err).To(HaveOccurred())
|
||||
|
||||
err = rdr.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
})
|
101
archive/archive_const_test.go
Normal file
101
archive/archive_const_test.go
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
libarc "github.com/nabbar/golib/archive"
|
||||
arcarc "github.com/nabbar/golib/archive/archive"
|
||||
arccmp "github.com/nabbar/golib/archive/compress"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func testingCompress(alg arccmp.Algorithm, str, ext string) {
|
||||
var (
|
||||
tmp arccmp.Algorithm
|
||||
jsn = []byte("\"" + str + "\"")
|
||||
res []byte
|
||||
)
|
||||
|
||||
Expect(libarc.ParseCompression(str)).To(Equal(alg))
|
||||
Expect(strings.ToLower(alg.String())).To(Equal(str))
|
||||
Expect(strings.ToLower(alg.Extension())).To(Equal(ext))
|
||||
Expect(alg.IsNone()).To(BeFalse())
|
||||
|
||||
err = tmp.UnmarshalJSON(jsn)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(tmp).To(Equal(alg))
|
||||
|
||||
res, err = tmp.MarshalJSON()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(res).To(Equal(jsn))
|
||||
}
|
||||
|
||||
func testingArchive(alg arcarc.Algorithm, str, ext string) {
|
||||
var (
|
||||
tmp arcarc.Algorithm
|
||||
jsn = []byte("\"" + str + "\"")
|
||||
res []byte
|
||||
)
|
||||
|
||||
Expect(libarc.ParseArchive(str)).To(Equal(alg))
|
||||
Expect(strings.ToLower(alg.String())).To(Equal(str))
|
||||
Expect(strings.ToLower(alg.Extension())).To(Equal(ext))
|
||||
Expect(alg.IsNone()).To(BeFalse())
|
||||
|
||||
err = tmp.UnmarshalJSON(jsn)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(tmp).To(Equal(alg))
|
||||
|
||||
res, err = tmp.MarshalJSON()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(res).To(Equal(jsn))
|
||||
}
|
||||
|
||||
var _ = Describe("archive/archive/algorithm", func() {
|
||||
Context("Using algorithm const", func() {
|
||||
It("gzip must succeed", func() {
|
||||
testingCompress(arccmp.Gzip, "gzip", ".gz")
|
||||
})
|
||||
It("bzip2 must succeed", func() {
|
||||
testingCompress(arccmp.Bzip2, "bzip2", ".bz2")
|
||||
})
|
||||
It("lz4 must succeed", func() {
|
||||
testingCompress(arccmp.LZ4, "lz4", ".lz4")
|
||||
})
|
||||
It("xz must succeed", func() {
|
||||
testingCompress(arccmp.XZ, "xz", ".xz")
|
||||
})
|
||||
It("tar must succeed", func() {
|
||||
testingArchive(arcarc.Tar, "tar", ".tar")
|
||||
})
|
||||
It("zip must succeed", func() {
|
||||
testingArchive(arcarc.Zip, "zip", ".zip")
|
||||
})
|
||||
})
|
||||
})
|
118
archive/archive_gzip_test.go
Normal file
118
archive/archive_gzip_test.go
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive_test
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
libarc "github.com/nabbar/golib/archive"
|
||||
arccmp "github.com/nabbar/golib/archive/compress"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("archive/compress/gzip", func() {
|
||||
Context("Write/Read a gzip compressed file", func() {
|
||||
It("Create a gzip compressed file must succeed", func() {
|
||||
var (
|
||||
hdf *os.File
|
||||
buf *bufio.Writer
|
||||
wrt io.WriteCloser
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
arc[arccmp.Gzip.String()] = "lorem_ipsum" + arccmp.Gzip.Extension()
|
||||
|
||||
hdf, err = os.Create(arc[arccmp.Gzip.String()])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hdf).ToNot(BeNil())
|
||||
|
||||
wrt, err = arccmp.Gzip.Writer(hdf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(wrt).ToNot(BeNil())
|
||||
|
||||
buf = bufio.NewWriter(wrt)
|
||||
_, err = buf.WriteString(loremIpsum)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = buf.Flush()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Sync()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = wrt.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("Detect and Extract a gzip compressed file must succeed", func() {
|
||||
var (
|
||||
hdf *os.File
|
||||
alg arccmp.Algorithm
|
||||
rdr io.ReadCloser
|
||||
buf *bufio.Reader
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
hdf, err = os.Open(arc[arccmp.Gzip.String()])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hdf).ToNot(BeNil())
|
||||
|
||||
alg, rdr, err = libarc.DetectCompression(hdf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rdr).ToNot(BeNil())
|
||||
Expect(alg).To(Equal(arccmp.Gzip))
|
||||
|
||||
buf = bufio.NewReader(rdr)
|
||||
_, err = io.Copy(io.Discard, buf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = buf.UnreadByte()
|
||||
Expect(err).To(HaveOccurred())
|
||||
|
||||
err = rdr.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
})
|
118
archive/archive_lz4_test.go
Normal file
118
archive/archive_lz4_test.go
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive_test
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
libarc "github.com/nabbar/golib/archive"
|
||||
arccmp "github.com/nabbar/golib/archive/compress"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("archive/compress/lz4", func() {
|
||||
Context("Write/Read a lz4 compressed file", func() {
|
||||
It("Create a lz4 compressed file must succeed", func() {
|
||||
var (
|
||||
hdf *os.File
|
||||
buf *bufio.Writer
|
||||
wrt io.WriteCloser
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
arc[arccmp.LZ4.String()] = "lorem_ipsum" + arccmp.LZ4.Extension()
|
||||
|
||||
hdf, err = os.Create(arc[arccmp.LZ4.String()])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hdf).ToNot(BeNil())
|
||||
|
||||
wrt, err = arccmp.LZ4.Writer(hdf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(wrt).ToNot(BeNil())
|
||||
|
||||
buf = bufio.NewWriter(wrt)
|
||||
_, err = buf.WriteString(loremIpsum)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = buf.Flush()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Sync()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = wrt.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("Detect and Extract a lz4 compressed file must succeed", func() {
|
||||
var (
|
||||
hdf *os.File
|
||||
alg arccmp.Algorithm
|
||||
rdr io.ReadCloser
|
||||
buf *bufio.Reader
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
hdf, err = os.Open(arc[arccmp.LZ4.String()])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hdf).ToNot(BeNil())
|
||||
|
||||
alg, rdr, err = libarc.DetectCompression(hdf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rdr).ToNot(BeNil())
|
||||
Expect(alg).To(Equal(arccmp.LZ4))
|
||||
|
||||
buf = bufio.NewReader(rdr)
|
||||
_, err = io.Copy(io.Discard, buf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = buf.UnreadByte()
|
||||
Expect(err).To(HaveOccurred())
|
||||
|
||||
err = rdr.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
})
|
121
archive/archive_suite_test.go
Normal file
121
archive/archive_suite_test.go
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive_test
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
/*
|
||||
Using https://onsi.github.io/ginkgo/
|
||||
Running with $> ginkgo -cover .
|
||||
*/
|
||||
|
||||
type EmptyStruct struct{}
|
||||
|
||||
var (
|
||||
err error
|
||||
lst = make(map[string]string, 0)
|
||||
arc = make(map[string]string, 0)
|
||||
dst string
|
||||
)
|
||||
|
||||
func rnd(min, max int) int {
|
||||
diff := big.NewInt(int64(max - min))
|
||||
n, _ := rand.Int(rand.Reader, diff)
|
||||
return min + int(n.Int64())
|
||||
}
|
||||
|
||||
// TestGolibEncodingAESHelper tests the Golib AES Encoding Helper function.
|
||||
func TestGolibArchiveHelper(t *testing.T) {
|
||||
time.Sleep(500 * time.Millisecond) // Adding delay for better testing synchronization
|
||||
RegisterFailHandler(Fail) // Registering fail handler for better test failure reporting
|
||||
RunSpecs(t, "Archive Helper Suite") // Running the test suite for Encoding AES Helper
|
||||
}
|
||||
|
||||
var _ = BeforeSuite(func() {
|
||||
for i := 1; i <= 5; i++ {
|
||||
p := filepath.Join(strings.Replace(reflect.TypeOf(EmptyStruct{}).PkgPath(), "_test", "", -1), "lorem_ipsum_"+strconv.Itoa(i)+".txt")
|
||||
lst[filepath.Base(p)] = p
|
||||
}
|
||||
|
||||
dst = filepath.Join(strings.Replace(reflect.TypeOf(EmptyStruct{}).PkgPath(), "_test", "", -1), "extract_all_dir")
|
||||
|
||||
var (
|
||||
w *os.File
|
||||
n int
|
||||
m = len(loremIpsum)
|
||||
)
|
||||
|
||||
for f := range lst {
|
||||
w, err = os.Create(filepath.Base(f))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(w).ToNot(BeNil())
|
||||
|
||||
l := rnd(10, m)
|
||||
p := rnd(0, m-l)
|
||||
n, err = w.Write([]byte(loremIpsum[p : p+l]))
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(n).To(BeEquivalentTo(l))
|
||||
|
||||
err = w.Sync()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = w.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
})
|
||||
|
||||
var _ = AfterSuite(func() {
|
||||
for b := range lst {
|
||||
_ = os.Remove(b)
|
||||
}
|
||||
|
||||
for _, b := range arc {
|
||||
_ = os.Remove(b)
|
||||
}
|
||||
|
||||
for strings.Contains(dst, string(filepath.Separator)) && len(dst) > 3 {
|
||||
_ = os.RemoveAll(dst)
|
||||
dst = filepath.Dir(dst)
|
||||
}
|
||||
|
||||
if len(dst) > 3 {
|
||||
_ = os.RemoveAll(dst)
|
||||
}
|
||||
})
|
208
archive/archive_tar_test.go
Normal file
208
archive/archive_tar_test.go
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive_test
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
libarc "github.com/nabbar/golib/archive"
|
||||
arcarc "github.com/nabbar/golib/archive/archive"
|
||||
arctps "github.com/nabbar/golib/archive/archive/types"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("archive/archive/tar", func() {
|
||||
Context("Write/Read a tar archive file", func() {
|
||||
It("Create a tar archive must succeed", func() {
|
||||
var (
|
||||
hdf *os.File
|
||||
wrt arctps.Writer
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
arc[arcarc.Tar.String()] = "lorem_ipsum" + arcarc.Tar.Extension()
|
||||
|
||||
hdf, err = os.Create(arc[arcarc.Tar.String()])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hdf).ToNot(BeNil())
|
||||
|
||||
wrt, err = arcarc.Tar.Writer(hdf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(wrt).ToNot(BeNil())
|
||||
|
||||
for f, p := range lst {
|
||||
var (
|
||||
i fs.FileInfo
|
||||
h *os.File
|
||||
)
|
||||
|
||||
i, err = os.Stat(f)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(i).ToNot(BeNil())
|
||||
|
||||
h, err = os.Open(f)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(h).ToNot(BeNil())
|
||||
|
||||
err = wrt.Add(i, h, p, "")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = h.Close()
|
||||
Expect(err).To(HaveOccurred())
|
||||
}
|
||||
|
||||
err = hdf.Sync()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = wrt.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Close()
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("Detect and Extract a tar archive must succeed", func() {
|
||||
var (
|
||||
hdf *os.File
|
||||
alg arcarc.Algorithm
|
||||
rdr arctps.Reader
|
||||
fnd []string
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
hdf, err = os.Open(arc[arcarc.Tar.String()])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hdf).ToNot(BeNil())
|
||||
|
||||
alg, rdr, _, err = libarc.DetectArchive(hdf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rdr).ToNot(BeNil())
|
||||
Expect(alg).To(Equal(arcarc.Tar))
|
||||
|
||||
fnd, err = rdr.List()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(fnd).ToNot(BeNil())
|
||||
|
||||
for _, g := range fnd {
|
||||
f, ok := lst[filepath.Base(g)]
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(g).To(Equal(f))
|
||||
}
|
||||
|
||||
for _, f := range lst {
|
||||
var (
|
||||
i fs.FileInfo
|
||||
r io.ReadCloser
|
||||
n int64
|
||||
)
|
||||
Expect(rdr.Has(f)).To(BeTrue())
|
||||
|
||||
i, err = rdr.Info(f)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(i).ToNot(BeNil())
|
||||
|
||||
r, err = rdr.Get(f)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(r).ToNot(BeNil())
|
||||
|
||||
n, err = io.Copy(io.Discard, r)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(n).To(BeEquivalentTo(i.Size()))
|
||||
|
||||
err = r.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
err = rdr.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Close()
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("Detect and Extract a tar archive with walk must succeed", func() {
|
||||
var (
|
||||
hdf *os.File
|
||||
alg arcarc.Algorithm
|
||||
rdr arctps.Reader
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
hdf, err = os.Open(arc[arcarc.Tar.String()])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hdf).ToNot(BeNil())
|
||||
|
||||
alg, rdr, _, err = arcarc.Detect(hdf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rdr).ToNot(BeNil())
|
||||
Expect(alg).To(Equal(arcarc.Tar))
|
||||
|
||||
rdr.Walk(func(i fs.FileInfo, r io.ReadCloser, f, t string) bool {
|
||||
g, ok := lst[filepath.Base(f)]
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(f).To(Equal(g))
|
||||
|
||||
Expect(i).ToNot(BeNil())
|
||||
Expect(r).ToNot(BeNil())
|
||||
|
||||
var n int64
|
||||
n, err = io.Copy(io.Discard, r)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(n).To(BeEquivalentTo(i.Size()))
|
||||
|
||||
err = r.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
err = rdr.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Close()
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
})
|
||||
})
|
123
archive/archive_tgz_test.go
Normal file
123
archive/archive_tgz_test.go
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive_test
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
|
||||
libarc "github.com/nabbar/golib/archive"
|
||||
arcarc "github.com/nabbar/golib/archive/archive"
|
||||
arctps "github.com/nabbar/golib/archive/archive/types"
|
||||
arccmp "github.com/nabbar/golib/archive/compress"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("archive/tar+gzip with extract all", func() {
|
||||
Context("Create a tar+gzip archive file and extract it with extract all", func() {
|
||||
It("Create a tar archive must succeed", func() {
|
||||
var (
|
||||
hdf *os.File
|
||||
gzp io.WriteCloser
|
||||
wrt arctps.Writer
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
arc[arcarc.Tar.String()+arccmp.Gzip.String()] = "lorem_ipsum" + arcarc.Tar.Extension() + arccmp.Gzip.Extension()
|
||||
hdf, err = os.Create(arc[arcarc.Tar.String()+arccmp.Gzip.String()])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hdf).ToNot(BeNil())
|
||||
|
||||
gzp, err = arccmp.Gzip.Writer(hdf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(gzp).ToNot(BeNil())
|
||||
|
||||
wrt, err = arcarc.Tar.Writer(gzp)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(wrt).ToNot(BeNil())
|
||||
|
||||
for f, p := range lst {
|
||||
var (
|
||||
i fs.FileInfo
|
||||
h *os.File
|
||||
)
|
||||
|
||||
i, err = os.Stat(f)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(i).ToNot(BeNil())
|
||||
|
||||
h, err = os.Open(f)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(h).ToNot(BeNil())
|
||||
|
||||
err = wrt.Add(i, h, p, "")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = h.Close()
|
||||
Expect(err).To(HaveOccurred())
|
||||
}
|
||||
|
||||
err = hdf.Sync()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = wrt.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = gzp.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("Detect all a tar+gzip archive must succeed", func() {
|
||||
var hdf *os.File
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
hdf, err = os.Open(arc[arcarc.Tar.String()+arccmp.Gzip.String()])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hdf).ToNot(BeNil())
|
||||
|
||||
err = libarc.ExtractAll(hdf, arc[arcarc.Tar.String()+arccmp.Gzip.String()], dst)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
})
|
118
archive/archive_xz_test.go
Normal file
118
archive/archive_xz_test.go
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive_test
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
libarc "github.com/nabbar/golib/archive"
|
||||
arccmp "github.com/nabbar/golib/archive/compress"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("archive/compress/xz", func() {
|
||||
Context("Write/Read a xz compressed file", func() {
|
||||
It("Create a xz compressed file must succeed", func() {
|
||||
var (
|
||||
hdf *os.File
|
||||
buf *bufio.Writer
|
||||
wrt io.WriteCloser
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
arc[arccmp.XZ.String()] = "lorem_ipsum" + arccmp.XZ.Extension()
|
||||
|
||||
hdf, err = os.Create(arc[arccmp.XZ.String()])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hdf).ToNot(BeNil())
|
||||
|
||||
wrt, err = arccmp.XZ.Writer(hdf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(wrt).ToNot(BeNil())
|
||||
|
||||
buf = bufio.NewWriter(wrt)
|
||||
_, err = buf.WriteString(loremIpsum)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = buf.Flush()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Sync()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = wrt.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("Detect and Extract a xz compressed file must succeed", func() {
|
||||
var (
|
||||
hdf *os.File
|
||||
alg arccmp.Algorithm
|
||||
rdr io.ReadCloser
|
||||
buf *bufio.Reader
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
hdf, err = os.Open(arc[arccmp.XZ.String()])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hdf).ToNot(BeNil())
|
||||
|
||||
alg, rdr, err = libarc.DetectCompression(hdf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rdr).ToNot(BeNil())
|
||||
Expect(alg).To(Equal(arccmp.XZ))
|
||||
|
||||
buf = bufio.NewReader(rdr)
|
||||
_, err = io.Copy(io.Discard, buf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = buf.UnreadByte()
|
||||
Expect(err).To(HaveOccurred())
|
||||
|
||||
err = rdr.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
})
|
212
archive/archive_zip_test.go
Normal file
212
archive/archive_zip_test.go
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive_test
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
libarc "github.com/nabbar/golib/archive"
|
||||
arcarc "github.com/nabbar/golib/archive/archive"
|
||||
arctps "github.com/nabbar/golib/archive/archive/types"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("archive/archive/zip", func() {
|
||||
Context("Write/Read a zip archive file", func() {
|
||||
It("Create a zip archive must succeed", func() {
|
||||
var (
|
||||
hdf *os.File
|
||||
wrt arctps.Writer
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
arc[arcarc.Zip.String()] = "lorem_ipsum" + arcarc.Zip.Extension()
|
||||
|
||||
hdf, err = os.Create(arc[arcarc.Zip.String()])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hdf).ToNot(BeNil())
|
||||
|
||||
wrt, err = arcarc.Zip.Writer(hdf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(wrt).ToNot(BeNil())
|
||||
|
||||
for f, p := range lst {
|
||||
var (
|
||||
i fs.FileInfo
|
||||
h *os.File
|
||||
)
|
||||
|
||||
i, err = os.Stat(f)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(i).ToNot(BeNil())
|
||||
|
||||
h, err = os.Open(f)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(h).ToNot(BeNil())
|
||||
|
||||
err = wrt.Add(i, h, p, "")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = h.Close()
|
||||
Expect(err).To(HaveOccurred())
|
||||
}
|
||||
|
||||
err = hdf.Sync()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = wrt.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Close()
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("Detect and Extract a zip archive must succeed", func() {
|
||||
var (
|
||||
hdf *os.File
|
||||
alg arcarc.Algorithm
|
||||
rdr arctps.Reader
|
||||
fnd []string
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
i, e := os.Stat(arc[arcarc.Zip.String()])
|
||||
Expect(e).ToNot(HaveOccurred())
|
||||
Expect(i).ToNot(BeNil())
|
||||
|
||||
hdf, err = os.Open(arc[arcarc.Zip.String()])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hdf).ToNot(BeNil())
|
||||
|
||||
alg, rdr, _, err = libarc.DetectArchive(hdf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rdr).ToNot(BeNil())
|
||||
Expect(alg).To(Equal(arcarc.Zip))
|
||||
|
||||
fnd, err = rdr.List()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(fnd).ToNot(BeNil())
|
||||
|
||||
for _, g := range fnd {
|
||||
f, ok := lst[filepath.Base(g)]
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(g).To(Equal(f))
|
||||
}
|
||||
|
||||
for _, f := range lst {
|
||||
var (
|
||||
i fs.FileInfo
|
||||
r io.ReadCloser
|
||||
n int64
|
||||
)
|
||||
Expect(rdr.Has(f)).To(BeTrue())
|
||||
|
||||
i, err = rdr.Info(f)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(i).ToNot(BeNil())
|
||||
|
||||
r, err = rdr.Get(f)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(r).ToNot(BeNil())
|
||||
|
||||
n, err = io.Copy(io.Discard, r)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(n).To(BeEquivalentTo(i.Size()))
|
||||
|
||||
err = r.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
err = rdr.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Close()
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("Detect and Extract a zip archive with walk must succeed", func() {
|
||||
var (
|
||||
hdf *os.File
|
||||
alg arcarc.Algorithm
|
||||
rdr arctps.Reader
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
hdf, err = os.Open(arc[arcarc.Zip.String()])
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hdf).ToNot(BeNil())
|
||||
|
||||
alg, rdr, _, err = arcarc.Detect(hdf)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rdr).ToNot(BeNil())
|
||||
Expect(alg).To(Equal(arcarc.Zip))
|
||||
|
||||
rdr.Walk(func(i fs.FileInfo, r io.ReadCloser, f, t string) bool {
|
||||
g, ok := lst[filepath.Base(f)]
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(f).To(Equal(g))
|
||||
|
||||
Expect(i).ToNot(BeNil())
|
||||
Expect(r).ToNot(BeNil())
|
||||
|
||||
var n int64
|
||||
n, err = io.Copy(io.Discard, r)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(n).To(BeEquivalentTo(i.Size()))
|
||||
|
||||
err = r.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
err = rdr.Close()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = hdf.Close()
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
})
|
||||
})
|
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package bz2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
arcmod "github.com/nabbar/golib/archive/archive"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
const pkgName = "golib/archive/bz2"
|
||||
|
||||
const (
|
||||
ErrorParamEmpty liberr.CodeError = iota + arcmod.MinPkgArchiveBZ2
|
||||
ErrorFileSeek
|
||||
ErrorIOCopy
|
||||
)
|
||||
|
||||
func init() {
|
||||
if liberr.ExistInMapMessage(ErrorParamEmpty) {
|
||||
panic(fmt.Errorf("error code collision %s", pkgName))
|
||||
}
|
||||
liberr.RegisterIdFctMessage(ErrorParamEmpty, getMessage)
|
||||
}
|
||||
|
||||
func getMessage(code liberr.CodeError) (message string) {
|
||||
switch code {
|
||||
case liberr.UnknownError:
|
||||
return liberr.NullMessage
|
||||
case ErrorParamEmpty:
|
||||
return "given parameters is empty"
|
||||
case ErrorFileSeek:
|
||||
return "cannot seek into file"
|
||||
case ErrorIOCopy:
|
||||
return "io copy occurs error"
|
||||
}
|
||||
|
||||
return liberr.NullMessage
|
||||
}
|
79
archive/compress/encoding.go
Normal file
79
archive/compress/encoding.go
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package compress
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (a Algorithm) MarshalText() ([]byte, error) {
|
||||
return []byte(a.String()), nil
|
||||
}
|
||||
|
||||
func (a *Algorithm) UnmarshalText(b []byte) error {
|
||||
*a = None
|
||||
|
||||
s := strings.Trim(string(b), "\"")
|
||||
s = strings.Trim(s, "'")
|
||||
s = strings.TrimSpace(s)
|
||||
|
||||
switch {
|
||||
case strings.EqualFold(s, Gzip.String()):
|
||||
*a = Gzip
|
||||
case strings.EqualFold(s, Bzip2.String()):
|
||||
*a = Bzip2
|
||||
case strings.EqualFold(s, LZ4.String()):
|
||||
*a = LZ4
|
||||
case strings.EqualFold(s, XZ.String()):
|
||||
*a = XZ
|
||||
default:
|
||||
*a = None
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a Algorithm) MarshalJSON() ([]byte, error) {
|
||||
if a.IsNone() {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return append(append([]byte{'"'}, []byte(a.String())...), '"'), nil
|
||||
}
|
||||
|
||||
func (a *Algorithm) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
|
||||
if n := []byte("null"); bytes.Equal(b, n) {
|
||||
*a = None
|
||||
return nil
|
||||
} else if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return a.UnmarshalText([]byte(s))
|
||||
}
|
||||
}
|
76
archive/compress/interface.go
Normal file
76
archive/compress/interface.go
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package compress
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
)
|
||||
|
||||
func Parse(s string) Algorithm {
|
||||
var alg = None
|
||||
if e := alg.UnmarshalText([]byte(s)); e != nil {
|
||||
return None
|
||||
} else {
|
||||
return alg
|
||||
}
|
||||
}
|
||||
|
||||
func Detect(r io.Reader) (Algorithm, io.ReadCloser, error) {
|
||||
var (
|
||||
err error
|
||||
alg Algorithm
|
||||
bfr = bufio.NewReader(r)
|
||||
buf []byte
|
||||
res io.ReadCloser
|
||||
)
|
||||
|
||||
if buf, err = bfr.Peek(6); err != nil {
|
||||
return None, nil, err
|
||||
}
|
||||
|
||||
// Vérifier le type de compression
|
||||
switch {
|
||||
case Gzip.DetectHeader(buf): // gzip
|
||||
alg = Gzip
|
||||
case Bzip2.DetectHeader(buf): // bzip2
|
||||
alg = Bzip2
|
||||
case LZ4.DetectHeader(buf): // lz4
|
||||
alg = LZ4
|
||||
case XZ.DetectHeader(buf): // xz
|
||||
alg = XZ
|
||||
default:
|
||||
alg = None
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return None, nil, err
|
||||
} else if res, err = alg.Reader(bfr); err != nil {
|
||||
return None, nil, err
|
||||
} else {
|
||||
return alg, res, err
|
||||
}
|
||||
}
|
67
archive/compress/io.go
Normal file
67
archive/compress/io.go
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package compress
|
||||
|
||||
import (
|
||||
"compress/bzip2"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
|
||||
bz2 "github.com/dsnet/compress/bzip2"
|
||||
"github.com/pierrec/lz4/v4"
|
||||
"github.com/ulikunitz/xz"
|
||||
)
|
||||
|
||||
func (a Algorithm) Reader(r io.Reader) (io.ReadCloser, error) {
|
||||
switch a {
|
||||
case Bzip2:
|
||||
return io.NopCloser(bzip2.NewReader(r)), nil
|
||||
case Gzip:
|
||||
return gzip.NewReader(r)
|
||||
case LZ4:
|
||||
return io.NopCloser(lz4.NewReader(r)), nil
|
||||
case XZ:
|
||||
c, e := xz.NewReader(r)
|
||||
return io.NopCloser(c), e
|
||||
default:
|
||||
return io.NopCloser(r), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (a Algorithm) Writer(w io.WriteCloser) (io.WriteCloser, error) {
|
||||
switch a {
|
||||
case Bzip2:
|
||||
return bz2.NewWriter(w, nil)
|
||||
case Gzip:
|
||||
return gzip.NewWriter(w), nil
|
||||
case LZ4:
|
||||
return lz4.NewWriter(w), nil
|
||||
case XZ:
|
||||
return xz.NewWriter(w)
|
||||
default:
|
||||
return w, nil
|
||||
}
|
||||
}
|
96
archive/compress/types.go
Normal file
96
archive/compress/types.go
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package compress
|
||||
|
||||
import "bytes"
|
||||
|
||||
type Algorithm uint8
|
||||
|
||||
const (
|
||||
None Algorithm = iota
|
||||
Bzip2
|
||||
Gzip
|
||||
LZ4
|
||||
XZ
|
||||
)
|
||||
|
||||
func (a Algorithm) IsNone() bool {
|
||||
return a == None
|
||||
}
|
||||
|
||||
func (a Algorithm) String() string {
|
||||
switch a {
|
||||
case Gzip:
|
||||
return "gzip"
|
||||
case Bzip2:
|
||||
return "bzip2"
|
||||
case LZ4:
|
||||
return "lz4"
|
||||
case XZ:
|
||||
return "xz"
|
||||
default:
|
||||
return "none"
|
||||
}
|
||||
}
|
||||
|
||||
func (a Algorithm) Extension() string {
|
||||
switch a {
|
||||
case Gzip:
|
||||
return ".gz"
|
||||
case Bzip2:
|
||||
return ".bz2"
|
||||
case LZ4:
|
||||
return ".lz4"
|
||||
case XZ:
|
||||
return ".xz"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (a Algorithm) DetectHeader(h []byte) bool {
|
||||
if len(h) < 6 {
|
||||
return false
|
||||
}
|
||||
|
||||
switch a {
|
||||
case Gzip:
|
||||
exp := []byte{31, 139}
|
||||
return bytes.Equal(h[0:2], exp)
|
||||
case Bzip2:
|
||||
exp := []byte{'B', 'Z', 'h'}
|
||||
return bytes.Equal(h[0:3], exp) && h[3] >= '0' && h[3] <= '9'
|
||||
case LZ4:
|
||||
exp := []byte{0x04, 0x22, 0x4D, 0x18}
|
||||
return bytes.Equal(h[0:4], exp)
|
||||
case XZ:
|
||||
exp := []byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00}
|
||||
alt := []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
|
||||
return bytes.Equal(h[0:6], exp) || bytes.Equal(h[0:6], alt)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
arcmod "github.com/nabbar/golib/archive/archive"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
const pkgName = "golib/archive"
|
||||
|
||||
const (
|
||||
ErrorParamEmpty liberr.CodeError = iota + arcmod.MinPkgArchive
|
||||
ErrorFileSeek
|
||||
ErrorFileOpen
|
||||
ErrorFileClose
|
||||
ErrorDirCreate
|
||||
ErrorDirStat
|
||||
ErrorDirNotDir
|
||||
ErrorIOCopy
|
||||
)
|
||||
|
||||
func init() {
|
||||
if liberr.ExistInMapMessage(ErrorParamEmpty) {
|
||||
panic(fmt.Errorf("error code collision %s", pkgName))
|
||||
}
|
||||
liberr.RegisterIdFctMessage(ErrorParamEmpty, getMessage)
|
||||
}
|
||||
|
||||
func getMessage(code liberr.CodeError) (message string) {
|
||||
switch code {
|
||||
case liberr.UnknownError:
|
||||
return liberr.NullMessage
|
||||
case ErrorParamEmpty:
|
||||
return "given parameters is empty"
|
||||
case ErrorFileSeek:
|
||||
return "cannot seek into file"
|
||||
case ErrorFileOpen:
|
||||
return "cannot open file"
|
||||
case ErrorFileClose:
|
||||
return "closing file occurs error"
|
||||
case ErrorDirCreate:
|
||||
return "make directory occurs error"
|
||||
case ErrorDirStat:
|
||||
return "checking directory occurs error"
|
||||
case ErrorDirNotDir:
|
||||
return "directory given is not a directory"
|
||||
case ErrorIOCopy:
|
||||
return "error occurs when io copy"
|
||||
}
|
||||
|
||||
return liberr.NullMessage
|
||||
}
|
185
archive/extract.go
Normal file
185
archive/extract.go
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
arcarc "github.com/nabbar/golib/archive/archive"
|
||||
arctps "github.com/nabbar/golib/archive/archive/types"
|
||||
arccmp "github.com/nabbar/golib/archive/compress"
|
||||
)
|
||||
|
||||
func ExtractAll(r io.ReadCloser, archiveName, destination string) error {
|
||||
var (
|
||||
e error
|
||||
n string
|
||||
a arccmp.Algorithm
|
||||
o io.ReadCloser
|
||||
)
|
||||
|
||||
if r == nil {
|
||||
return fs.ErrInvalid
|
||||
}
|
||||
|
||||
for e == nil {
|
||||
a, o, e = DetectCompression(r)
|
||||
|
||||
if a.IsNone() {
|
||||
break
|
||||
}
|
||||
|
||||
n = strings.TrimSuffix(filepath.Base(archiveName), a.Extension())
|
||||
return ExtractAll(o, n, destination)
|
||||
}
|
||||
|
||||
var (
|
||||
b arcarc.Algorithm
|
||||
z arctps.Reader
|
||||
)
|
||||
|
||||
if b, z, r, e = DetectArchive(o); e != nil {
|
||||
return e
|
||||
} else if b.IsNone() {
|
||||
return writeFile(archiveName, destination, r, nil)
|
||||
} else if z == nil {
|
||||
return fs.ErrInvalid
|
||||
} else {
|
||||
var err error
|
||||
|
||||
z.Walk(func(info fs.FileInfo, closer io.ReadCloser, dst, target string) bool {
|
||||
defer func() {
|
||||
if closer != nil {
|
||||
_ = closer.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
if info.IsDir() {
|
||||
if e = createPath(filepath.Join(destination, cleanPath(dst)), info.Mode()); e != nil {
|
||||
err = e
|
||||
return false
|
||||
}
|
||||
} else if info.Mode()&os.ModeSymlink != 0 {
|
||||
if e = writeSymLink(true, dst, target, destination); e != nil {
|
||||
err = e
|
||||
return false
|
||||
}
|
||||
} else if info.Mode()&os.ModeDevice != 0 {
|
||||
if e = writeSymLink(false, dst, target, destination); e != nil {
|
||||
err = e
|
||||
return false
|
||||
}
|
||||
} else if info.Mode().IsRegular() {
|
||||
if e = writeFile(dst, destination, closer, info); e != nil {
|
||||
err = e
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// prevent file cursor not at EOF of current file for TAPE Archive
|
||||
_, _ = io.Copy(io.Discard, closer)
|
||||
return true
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func cleanPath(path string) string {
|
||||
for strings.Contains(path, ".."+string(filepath.Separator)) {
|
||||
path = filepath.Clean(path)
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
func createPath(dest string, info os.FileMode) error {
|
||||
if i, err := os.Stat(dest); err == nil {
|
||||
if i.IsDir() {
|
||||
return nil
|
||||
} else {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
} else if os.IsNotExist(err) {
|
||||
if err = createPath(filepath.Dir(dest), info); err != nil {
|
||||
return err
|
||||
} else if info != 0 {
|
||||
return os.Mkdir(dest, info)
|
||||
} else {
|
||||
return os.Mkdir(dest, 0755)
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func writeFile(name, dest string, r io.ReadCloser, i fs.FileInfo) error {
|
||||
var (
|
||||
dst = filepath.Join(dest, cleanPath(name))
|
||||
hdf *os.File
|
||||
err error
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if hdf != nil {
|
||||
_ = hdf.Sync()
|
||||
_ = hdf.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
if err = createPath(filepath.Dir(dst), 0); err != nil {
|
||||
return err
|
||||
} else if hdf, err = os.Create(dst); err != nil {
|
||||
return err
|
||||
} else if _, err = io.Copy(hdf, r); err != nil {
|
||||
return err
|
||||
} else if i != nil {
|
||||
if err = os.Chmod(dst, i.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeSymLink(isSymLink bool, name, target, dest string) error {
|
||||
var (
|
||||
dst = filepath.Join(dest, cleanPath(name))
|
||||
err error
|
||||
)
|
||||
|
||||
if err = createPath(filepath.Dir(dst), 0); err != nil {
|
||||
return err
|
||||
} else if isSymLink {
|
||||
return os.Symlink(target, dst)
|
||||
} else {
|
||||
return os.Link(target, dst)
|
||||
}
|
||||
}
|
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package gzip
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
arcmod "github.com/nabbar/golib/archive/archive"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
const pkgName = "golib/archive/gzip"
|
||||
|
||||
const (
|
||||
ErrorParamEmpty liberr.CodeError = iota + arcmod.MinPkgArchiveGZip
|
||||
ErrorParamMismatching
|
||||
ErrorGZCreate
|
||||
ErrorGZReader
|
||||
ErrorFileSeek
|
||||
ErrorIOCopy
|
||||
ErrorFileOpen
|
||||
)
|
||||
|
||||
func init() {
|
||||
if liberr.ExistInMapMessage(ErrorParamEmpty) {
|
||||
panic(fmt.Errorf("error code collision %s", pkgName))
|
||||
}
|
||||
liberr.RegisterIdFctMessage(ErrorParamEmpty, getMessage)
|
||||
}
|
||||
|
||||
func getMessage(code liberr.CodeError) (message string) {
|
||||
switch code {
|
||||
case liberr.UnknownError:
|
||||
return liberr.NullMessage
|
||||
case ErrorParamEmpty:
|
||||
return "given parameters is empty"
|
||||
case ErrorParamMismatching:
|
||||
return "given parameters is not matching the awaiting scope"
|
||||
case ErrorGZCreate:
|
||||
return "cannot create the GZip archive"
|
||||
case ErrorGZReader:
|
||||
return "cannot create new reader GZip"
|
||||
case ErrorFileSeek:
|
||||
return "cannot seek into file"
|
||||
case ErrorIOCopy:
|
||||
return "io copy occurs error"
|
||||
case ErrorFileOpen:
|
||||
return "cannot open file content"
|
||||
}
|
||||
|
||||
return liberr.NullMessage
|
||||
}
|
@@ -1,91 +0,0 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2021 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
package gzip
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
func Create(archive io.WriteSeeker, stripPath string, comment string, content ...string) (bool, liberr.Error) {
|
||||
var (
|
||||
w *gzip.Writer
|
||||
f *os.File
|
||||
|
||||
err error
|
||||
)
|
||||
|
||||
if len(content) != 1 {
|
||||
//nolint #goerr113
|
||||
return false, ErrorParamMismatching.Error(fmt.Errorf("content path must be limited to strictly one contents"))
|
||||
}
|
||||
|
||||
if _, err = archive.Seek(0, io.SeekStart); err != nil {
|
||||
return false, ErrorFileSeek.Error(err)
|
||||
}
|
||||
|
||||
if _, err = os.Stat(content[0]); err != nil {
|
||||
return false, ErrorParamEmpty.Error(err)
|
||||
}
|
||||
|
||||
w = gzip.NewWriter(archive)
|
||||
|
||||
defer func() {
|
||||
if w != nil {
|
||||
_ = w.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
if f, err = os.Open(content[0]); err != nil {
|
||||
return false, ErrorFileOpen.Error(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if f != nil {
|
||||
_ = f.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
if _, err = io.Copy(w, f); err != nil {
|
||||
return false, ErrorIOCopy.Error(err)
|
||||
}
|
||||
|
||||
if err = w.Close(); err != nil {
|
||||
return false, ErrorGZCreate.Error(err)
|
||||
}
|
||||
|
||||
if _, err = archive.Seek(0, io.SeekStart); err != nil {
|
||||
return false, ErrorFileSeek.Error(err)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package gzipreader
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
)
|
||||
|
||||
type GZipReader interface {
|
||||
io.Reader
|
||||
|
||||
LenCompressed() int64
|
||||
LenUnCompressed() int64
|
||||
|
||||
Rate() float64
|
||||
}
|
||||
|
||||
// GzipReader is used to GZIP a io.reader on fly.
|
||||
// The given io.reader is not a gzip reader but the result is a GZipped reader
|
||||
func GzipReader(r io.Reader) GZipReader {
|
||||
b := bytes.NewBuffer(make([]byte, 0, 32*1024))
|
||||
|
||||
return &gzr{
|
||||
r: r,
|
||||
b: b,
|
||||
z: gzip.NewWriter(b),
|
||||
}
|
||||
}
|
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package gzipreader
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
type gzr struct {
|
||||
r io.Reader
|
||||
b *bytes.Buffer
|
||||
z *gzip.Writer
|
||||
nc int64
|
||||
nu int64
|
||||
}
|
||||
|
||||
func (o *gzr) Read(p []byte) (n int, err error) {
|
||||
var (
|
||||
s []byte
|
||||
|
||||
er error
|
||||
nr int
|
||||
|
||||
ew error
|
||||
nw int
|
||||
)
|
||||
|
||||
if i := cap(p); i > o.b.Cap() || i < 1 {
|
||||
s = make([]byte, 0, o.b.Cap())
|
||||
} else {
|
||||
s = make([]byte, 0, i)
|
||||
}
|
||||
|
||||
nr, er = o.r.Read(s)
|
||||
o.nu += int64(nr)
|
||||
|
||||
if er != nil && !errors.Is(er, io.EOF) {
|
||||
return 0, err
|
||||
} else if nr > 0 {
|
||||
nw, ew = o.z.Write(s)
|
||||
}
|
||||
|
||||
if ew != nil {
|
||||
return 0, ew
|
||||
} else if nw != nr {
|
||||
return 0, errors.New("invalid write buffer")
|
||||
} else if er != nil && errors.Is(er, io.EOF) {
|
||||
if ew = o.z.Close(); ew != nil {
|
||||
return 0, ew
|
||||
}
|
||||
}
|
||||
|
||||
copy(p, o.b.Bytes())
|
||||
o.b.Reset()
|
||||
o.nc += int64(len(p))
|
||||
|
||||
return len(p), er
|
||||
}
|
||||
|
||||
func (o *gzr) LenCompressed() int64 {
|
||||
return o.nc
|
||||
}
|
||||
|
||||
func (o *gzr) LenUnCompressed() int64 {
|
||||
return o.nu
|
||||
}
|
||||
|
||||
func (o *gzr) Rate() float64 {
|
||||
return 1 - float64(o.nc/o.nu)
|
||||
}
|
50
archive/interface.go
Normal file
50
archive/interface.go
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
arcarc "github.com/nabbar/golib/archive/archive"
|
||||
arctps "github.com/nabbar/golib/archive/archive/types"
|
||||
arccmp "github.com/nabbar/golib/archive/compress"
|
||||
)
|
||||
|
||||
func ParseCompression(s string) arccmp.Algorithm {
|
||||
return arccmp.Parse(s)
|
||||
}
|
||||
|
||||
func DetectCompression(r io.Reader) (arccmp.Algorithm, io.ReadCloser, error) {
|
||||
return arccmp.Detect(r)
|
||||
}
|
||||
|
||||
func ParseArchive(s string) arcarc.Algorithm {
|
||||
return arcarc.Parse(s)
|
||||
}
|
||||
|
||||
func DetectArchive(r io.ReadCloser) (arcarc.Algorithm, arctps.Reader, io.ReadCloser, error) {
|
||||
return arcarc.Detect(r)
|
||||
}
|
790
archive/lorem_ipsum_test.go
Normal file
790
archive/lorem_ipsum_test.go
Normal file
@@ -0,0 +1,790 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive_test
|
||||
|
||||
const loremIpsum = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec consectetur
|
||||
leo, non faucibus lectus. Aenean sed felis et ex porttitor viverra quis in
|
||||
felis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per
|
||||
inceptos himenaeos. Mauris gravida lorem nisl, non pretium metus tristique sed.
|
||||
In pretium mauris at tellus pharetra accumsan. Vestibulum eget tortor mauris.
|
||||
Maecenas non pharetra turpis. Nunc lobortis consequat velit id maximus. Nunc eu
|
||||
metus sem.
|
||||
|
||||
Donec egestas sem non nisl iaculis, et auctor augue condimentum. Etiam pulvinar
|
||||
ligula ante, vitae hendrerit leo gravida sit amet. Integer dictum metus vel leo
|
||||
consequat, ac ultrices tortor tincidunt. Donec eros arcu, ornare vitae lorem
|
||||
ac, lacinia convallis urna. Mauris blandit at justo et hendrerit. Nam commodo
|
||||
augue arcu, mollis lacinia nisi facilisis at. Nulla iaculis quam nisl, et
|
||||
placerat nisl tincidunt vel. Nam bibendum nulla non luctus efficitur. Nunc quis
|
||||
tellus sapien. Vivamus laoreet porta fermentum. Ut posuere id risus sed
|
||||
scelerisque. Praesent leo nibh, hendrerit a risus a, pulvinar sollicitudin
|
||||
velit. Maecenas sed pharetra massa. Aliquam sed suscipit nisi. Nullam auctor
|
||||
tortor at faucibus ultrices. Mauris dictum eros ac fermentum facilisis.
|
||||
|
||||
Pellentesque varius pretium fringilla. Aenean nisi risus, tincidunt non quam
|
||||
ac, mattis venenatis mauris. Ut at facilisis est. Phasellus laoreet nibh at
|
||||
magna accumsan, sit amet ullamcorper magna laoreet. Duis sit amet tortor
|
||||
gravida sem convallis tristique. Praesent pharetra metus vitae scelerisque
|
||||
pretium. Phasellus a suscipit ex, finibus pellentesque elit. Proin ac tincidunt
|
||||
ipsum, vel dignissim quam. In vulputate turpis eget nibh bibendum blandit vitae
|
||||
sit amet eros. Proin eget tortor est. Curabitur sollicitudin elit mi, in
|
||||
efficitur velit eleifend ut. Orci varius natoque penatibus et magnis dis
|
||||
parturient montes, nascetur ridiculus mus. Curabitur tincidunt dui ligula, id
|
||||
vehicula turpis lacinia sed. Mauris egestas ullamcorper est sit amet iaculis.
|
||||
Sed nisl purus, commodo at vulputate sed, maximus pretium ipsum.
|
||||
|
||||
Donec fermentum nunc ac aliquam congue. Donec eu risus nec lorem pulvinar
|
||||
malesuada non id enim. Vestibulum sed tellus vitae sapien tincidunt molestie.
|
||||
Aenean vitae ante enim. Morbi malesuada volutpat laoreet. Suspendisse vehicula,
|
||||
leo nec mattis maximus, justo turpis viverra lorem, accumsan malesuada massa
|
||||
libero at tortor. Ut sed cursus quam, in rhoncus tortor. Vestibulum non
|
||||
scelerisque felis. Quisque tempor dolor id lorem rhoncus fringilla nec vitae
|
||||
ligula. Donec ac urna dignissim, tincidunt ex vel, vulputate felis.
|
||||
|
||||
Suspendisse sagittis, tellus sit amet fringilla sollicitudin, metus ligula
|
||||
faucibus nisl, tristique faucibus nisl mi vel eros. Vestibulum ante ipsum
|
||||
primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse
|
||||
quis metus laoreet, viverra tellus vitae, pretium velit. Suspendisse potenti.
|
||||
Quisque vulputate eget dolor id fermentum. Proin vel consectetur orci. Class
|
||||
aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos
|
||||
himenaeos. Nam at leo in enim sodales egestas tincidunt volutpat ex. Duis vel
|
||||
ornare sapien. Integer feugiat est semper tortor maximus, non rhoncus sapien
|
||||
dapibus. Phasellus tristique fermentum lorem, nec mattis ipsum volutpat eu.
|
||||
|
||||
Curabitur tempus erat viverra pulvinar scelerisque. Proin blandit turpis sed
|
||||
enim imperdiet, volutpat pretium diam tincidunt. Mauris feugiat rutrum lacus,
|
||||
eu ullamcorper ipsum auctor consectetur. Nulla placerat dolor in dolor tempor,
|
||||
non dignissim velit auctor. Praesent vehicula dui nunc, eu dictum sapien
|
||||
venenatis id. Sed et finibus turpis. Maecenas sollicitudin eros ac neque ornare
|
||||
congue. Praesent neque risus, malesuada sed mauris sed, fringilla interdum
|
||||
justo. Vestibulum porttitor quam sit amet nulla consequat, non posuere risus
|
||||
porta. Nulla tristique feugiat gravida. Aliquam erat volutpat. Fusce venenatis
|
||||
gravida ligula in pretium. Sed cursus sem non augue dignissim, at facilisis
|
||||
nunc dignissim. Curabitur scelerisque enim in ligula posuere, in malesuada elit
|
||||
commodo.
|
||||
|
||||
Vivamus magna dolor, efficitur et condimentum at, maximus eget massa. Nullam
|
||||
sit amet vestibulum est, et pellentesque sem. Nunc porta sem sit amet suscipit
|
||||
lobortis. Cras consequat ullamcorper velit, at dapibus erat cursus ut. Sed
|
||||
eleifend elit et libero eleifend rhoncus vitae quis velit. Nulla cursus diam
|
||||
vitae suscipit blandit. Vivamus condimentum, felis ut consectetur mattis, risus
|
||||
eros blandit nisl, sed dapibus orci quam quis sapien. Lorem ipsum dolor sit
|
||||
amet, consectetur adipiscing elit. Donec quis felis a eros consectetur
|
||||
sollicitudin. Fusce mattis orci et convallis luctus. Nullam aliquet viverra
|
||||
dapibus. Curabitur sit amet dolor rutrum, pretium metus a, ultricies ante.
|
||||
|
||||
Proin faucibus congue turpis, sit amet dignissim orci vestibulum eu. Cras
|
||||
consectetur augue a nisi congue, a posuere justo bibendum. Etiam erat erat,
|
||||
semper id enim sit amet, interdum facilisis magna. Suspendisse a augue quis sem
|
||||
lobortis pretium eget ut lorem. Vivamus lobortis dui id ex bibendum, at laoreet
|
||||
mi auctor. Nunc vestibulum tortor interdum nisl rhoncus mattis. Nullam at
|
||||
volutpat risus. Fusce vel pellentesque odio, id convallis elit. Aliquam sodales
|
||||
iaculis sapien, et gravida nunc fringilla et. In sed commodo diam, in accumsan
|
||||
velit. Nulla condimentum massa vitae erat consequat iaculis. Nulla facilisi.
|
||||
|
||||
Mauris sapien risus, tempus molestie viverra ut, consequat non tellus. Aliquam
|
||||
purus dolor, tristique sagittis orci ac, luctus efficitur libero. Integer
|
||||
maximus magna magna, id condimentum tellus molestie eget. Integer posuere lacus
|
||||
vel venenatis cursus. Ut auctor enim vitae felis elementum, vel blandit lorem
|
||||
fermentum. Orci varius natoque penatibus et magnis dis parturient montes,
|
||||
nascetur ridiculus mus. Pellentesque habitant morbi tristique senectus et netus
|
||||
et malesuada fames ac turpis egestas. Morbi convallis mattis odio a pulvinar.
|
||||
Vestibulum quis lacus posuere, faucibus est a, suscipit velit. Phasellus
|
||||
tincidunt neque enim, at tempor neque auctor sed. In sit amet nisl quis diam
|
||||
eleifend dapibus a vel nisl. Orci varius natoque penatibus et magnis dis
|
||||
parturient montes, nascetur ridiculus mus. Sed at dui vehicula dolor tincidunt
|
||||
auctor vitae sit amet turpis. Maecenas nisi sapien, porta sed volutpat non,
|
||||
imperdiet eu magna.
|
||||
|
||||
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
|
||||
cubilia curae; Curabitur vitae tempus nibh, in vulputate sem. Quisque a
|
||||
tincidunt mi, at porttitor dolor. Maecenas rhoncus sapien lectus, ut porta eros
|
||||
porta at. Mauris finibus purus sit amet leo mattis accumsan. Vivamus molestie
|
||||
dapibus iaculis. Donec sagittis mattis nunc nec dapibus. Nulla cursus non mi et
|
||||
malesuada. Fusce tempor nulla eget sagittis ultrices. Proin vel ipsum ac erat
|
||||
tempor semper consectetur ut sapien. Ut aliquet viverra magna, id mollis ligula
|
||||
interdum et. Morbi porta dapibus metus ac varius.
|
||||
|
||||
Nullam blandit quis nulla vitae volutpat. Etiam leo ante, mattis non congue
|
||||
sed, vulputate a augue. Cras eget tempor enim, semper mattis eros. Sed sed
|
||||
varius mi. Donec porta neque purus, vitae accumsan ante consequat vitae.
|
||||
Suspendisse luctus, sem quis convallis luctus, dolor sapien ultricies tellus,
|
||||
sagittis egestas ipsum odio eget augue. Nulla ut est a dui pulvinar ultrices ac
|
||||
nec augue. Vestibulum ultrices molestie libero, et aliquam erat sodales nec.
|
||||
Maecenas elementum finibus dolor, eu porta eros vulputate quis.
|
||||
|
||||
In sit amet pharetra lorem. Nulla dictum lectus ac odio mollis dapibus. Sed
|
||||
euismod bibendum orci vel posuere. Curabitur malesuada lobortis nunc id
|
||||
condimentum. Maecenas iaculis mi sit amet nunc cursus vehicula. Nam tristique
|
||||
vel purus vehicula auctor. Cras at ipsum nisi.
|
||||
|
||||
Aenean sit amet sem euismod, molestie purus condimentum, rutrum felis. Quisque
|
||||
nec porttitor nisl, id molestie massa. Donec venenatis blandit hendrerit. Nulla
|
||||
facilisi. Maecenas ultricies urna et ipsum sagittis, eget placerat est tempor.
|
||||
Sed commodo nisl eget lorem vulputate, quis malesuada dui facilisis. Integer ut
|
||||
placerat ligula. Pellentesque blandit mi et vestibulum blandit.
|
||||
|
||||
Fusce non erat turpis. Phasellus lobortis molestie nisi, nec luctus dolor
|
||||
posuere fringilla. Proin viverra ipsum a iaculis convallis. Morbi ac elit erat.
|
||||
Ut a lacus felis. Fusce volutpat, orci sed dapibus varius, lectus enim lobortis
|
||||
elit, ac elementum ipsum purus ac ligula. Duis posuere arcu et urna commodo
|
||||
posuere. Proin placerat nibh non pharetra tincidunt. Nam convallis ex enim, vel
|
||||
lacinia eros placerat at. Quisque laoreet risus non risus pellentesque, quis
|
||||
ultrices lectus posuere. Aliquam ut risus at ex dignissim porttitor. Vivamus
|
||||
non magna quis tellus venenatis viverra id nec orci.
|
||||
|
||||
Ut augue libero, luctus eget consequat facilisis, venenatis id nunc. Nam
|
||||
molestie ante a faucibus egestas. Integer fringilla laoreet fringilla. Quisque
|
||||
euismod scelerisque libero ac finibus. Sed porttitor sollicitudin mi at tempor.
|
||||
Nam at convallis tellus. Curabitur ornare elit a quam consectetur, sit amet
|
||||
pharetra elit sodales. In convallis tincidunt congue. Morbi vehicula aliquam
|
||||
sem. Cras urna sem, mollis vel viverra id, vestibulum sit amet est. Donec
|
||||
condimentum lacus ut mauris viverra auctor. Aenean turpis dui, condimentum sed
|
||||
varius ac, finibus vitae ex. Vivamus vehicula vehicula nibh consequat faucibus.
|
||||
Vivamus at lectus orci. Duis et sapien at metus laoreet rutrum sit amet
|
||||
fringilla nisi.
|
||||
|
||||
Duis feugiat lorem vel suscipit consectetur. Vivamus molestie diam urna, at
|
||||
egestas ante volutpat non. Fusce vitae justo a leo iaculis suscipit vitae id
|
||||
urna. Aliquam sit amet diam eu neque sollicitudin semper a elementum nisi.
|
||||
Vivamus aliquam diam eget nunc scelerisque placerat. Vestibulum pharetra at
|
||||
felis ut consectetur. Integer auctor mauris libero, id auctor nulla cursus
|
||||
consequat. Vivamus porta erat nec metus placerat, sit amet ultrices orci
|
||||
commodo. Integer tempus blandit iaculis. Donec sagittis, mi ultricies eleifend
|
||||
egestas, nisi odio posuere lacus, eu ultrices erat turpis vel est. Nullam
|
||||
scelerisque lectus et iaculis sodales. In quis diam fringilla sem eleifend
|
||||
hendrerit quis ut augue.
|
||||
|
||||
Cras non pulvinar urna. In id urna justo. Duis pellentesque enim in nunc
|
||||
hendrerit, vel suscipit libero venenatis. Phasellus egestas convallis neque,
|
||||
sit amet pretium nunc lacinia eu. Maecenas placerat justo vitae sem ultricies,
|
||||
ut luctus magna blandit. Donec in ligula vel arcu aliquet tristique. Nam
|
||||
imperdiet augue eget aliquam commodo. Pellentesque accumsan auctor sapien, in
|
||||
feugiat turpis. Pellentesque at purus at risus venenatis tempor. Ut vestibulum
|
||||
enim mi, eget blandit odio faucibus eu. Phasellus egestas, velit non egestas
|
||||
bibendum, mi leo ultrices massa, sed maximus erat turpis eget est. Suspendisse
|
||||
lacus lacus, finibus sed dolor ac, sagittis viverra metus. Cras velit nisi,
|
||||
malesuada eget metus nec, aliquet auctor mauris. Phasellus lobortis turpis
|
||||
neque, eu dictum nulla posuere vel.
|
||||
|
||||
Sed fermentum imperdiet tellus ac vulputate. Donec vel purus ullamcorper mi
|
||||
varius pulvinar. Proin feugiat vehicula massa in dignissim. Quisque posuere
|
||||
porttitor placerat. Aliquam erat volutpat. Vivamus sollicitudin vulputate
|
||||
metus, nec eleifend nulla. Morbi vitae cursus arcu. Aenean vel rutrum purus.
|
||||
Pellentesque sollicitudin libero a neque mattis, vitae convallis leo dictum.
|
||||
Aenean ex turpis, placerat at ultrices sit amet, consectetur id dui.
|
||||
|
||||
Praesent id tortor sagittis, sagittis nisi quis, scelerisque magna. Nulla non
|
||||
tortor sed dui rutrum pharetra. Aenean aliquam scelerisque metus in
|
||||
sollicitudin. Proin ac tincidunt nisl. Etiam tempus sollicitudin eleifend.
|
||||
Pellentesque vehicula nibh at sem bibendum, facilisis pellentesque diam
|
||||
volutpat. Integer ullamcorper mattis ligula eu semper. Ut dignissim laoreet
|
||||
magna, vitae ornare dui pretium vitae. Nullam consectetur, mi sit amet
|
||||
facilisis consequat, arcu risus tristique metus, sed hendrerit ligula erat ut
|
||||
mauris. Maecenas mi ex, porttitor vitae tellus at, commodo pulvinar sem. Donec
|
||||
ac imperdiet sapien, quis feugiat elit.
|
||||
|
||||
Vivamus porta, massa a vulputate viverra, odio quam laoreet nunc, nec vehicula
|
||||
ligula sapien vel ante. Nullam ut ante arcu. In non molestie turpis. Etiam nec
|
||||
efficitur tellus. Proin placerat diam vitae pellentesque congue. Fusce aliquam
|
||||
augue eu lectus pellentesque, et condimentum tortor volutpat. Donec semper
|
||||
sodales felis ut elementum. Curabitur suscipit lacus sit amet risus posuere, et
|
||||
porta quam pretium. Praesent aliquam luctus vulputate. In tincidunt, elit sed
|
||||
congue hendrerit, augue mi laoreet lacus, eu imperdiet est quam eget elit.
|
||||
Aliquam porta sit amet tortor in semper. Nullam nec nisl eu lectus sagittis
|
||||
lacinia vel a nisi.
|
||||
|
||||
Ut suscipit, ligula nec blandit varius, neque mi tempus odio, ut bibendum massa
|
||||
enim nec libero. Nulla fermentum tristique nisi at tempor. Sed nec pharetra
|
||||
felis, et tempor quam. Mauris lobortis arcu sed posuere pretium. Aenean eu
|
||||
lacinia ex, aliquet dignissim dui. Integer lobortis et risus ut porta. Donec
|
||||
dapibus viverra quam, et vulputate metus consequat ut. Suspendisse accumsan et
|
||||
orci vitae ornare. Curabitur volutpat orci quis lacus pharetra, ut condimentum
|
||||
eros pellentesque. Vivamus scelerisque mauris eget luctus vestibulum. Fusce
|
||||
placerat, tellus in tincidunt tempor, est dolor ultrices urna, id euismod neque
|
||||
sapien nec metus. Praesent lacinia eget sapien sed accumsan. Maecenas tempor
|
||||
nunc ac sapien aliquet, eu sagittis metus ornare. Praesent ut urna tellus.
|
||||
Donec elementum sem diam. Sed pretium consectetur massa eget gravida.
|
||||
|
||||
Donec ut est ut velit tincidunt pretium eget ut massa. Ut tempor eget nunc eget
|
||||
egestas. In ac risus elementum, ornare metus vel, laoreet nisl. Ut auctor,
|
||||
risus facilisis pellentesque ornare, lacus ex scelerisque ex, a feugiat arcu mi
|
||||
vitae tortor. Ut venenatis finibus lorem sit amet pretium. Aliquam vel
|
||||
scelerisque sem. Vestibulum iaculis sed erat vel cursus. In volutpat sodales
|
||||
dignissim.
|
||||
|
||||
Donec nibh magna, scelerisque vel ante non, semper aliquam nisi. Ut ornare
|
||||
pellentesque sapien aliquam tristique. Donec convallis tempus magna, eu blandit
|
||||
felis finibus quis. Donec laoreet odio ut nisi aliquam venenatis. Nam
|
||||
consectetur a lorem bibendum accumsan. Vivamus leo neque, sollicitudin vel
|
||||
sodales quis, ultricies nec felis. Aenean luctus mauris nec imperdiet
|
||||
dignissim.
|
||||
|
||||
Mauris posuere nibh dui, ut luctus felis consequat et. Aenean odio nibh, tempor
|
||||
in sapien et, suscipit pulvinar ex. Vivamus molestie augue felis, non venenatis
|
||||
ante congue eu. Aliquam commodo feugiat augue at venenatis. Nulla sapien odio,
|
||||
posuere vel aliquet et, volutpat sed nunc. Aliquam eu pharetra sem. Nulla
|
||||
facilisi. Duis interdum leo lectus, quis finibus nisi euismod quis.
|
||||
|
||||
Fusce et neque vel tellus porta vulputate. Duis non ex turpis. Class aptent
|
||||
taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
|
||||
Sed eget risus at dolor consectetur suscipit sed sed sem. Sed pharetra lectus
|
||||
ante, sit amet malesuada felis euismod vitae. Vivamus condimentum dapibus erat,
|
||||
at varius urna condimentum sit amet. Morbi condimentum sapien est. Nulla
|
||||
malesuada erat nec semper scelerisque. Ut porta, risus eu elementum viverra,
|
||||
dui nulla vehicula purus, eu placerat magna sapien ut quam. Aliquam suscipit
|
||||
massa eget lacus ornare feugiat. Praesent sagittis aliquam malesuada. Aliquam
|
||||
quam turpis, efficitur non elit vitae, laoreet tristique erat. Proin at magna
|
||||
sollicitudin nulla aliquam ultrices ac id dui. Vestibulum facilisis sed leo
|
||||
vitae tempor. Donec id lorem pharetra, tempor mauris ut, convallis magna. Etiam
|
||||
feugiat est eget varius fringilla.
|
||||
|
||||
Cras tristique erat at justo maximus tempor. Pellentesque fringilla felis at
|
||||
magna luctus, vel posuere purus venenatis. Ut tristique ligula vitae metus
|
||||
euismod euismod. Ut et tortor eu dui malesuada dictum. Cras laoreet rutrum ante
|
||||
quis tincidunt. Aenean diam magna, tristique a erat a, efficitur posuere nisi.
|
||||
Vestibulum dapibus, tortor vitae malesuada vulputate, eros augue ullamcorper
|
||||
lacus, a facilisis turpis turpis vel dui. Class aptent taciti sociosqu ad
|
||||
litora torquent per conubia nostra, per inceptos himenaeos. Donec ultrices quam
|
||||
turpis, id tempor nulla accumsan in. Suspendisse scelerisque volutpat lectus, a
|
||||
placerat lorem sodales in. Suspendisse porttitor felis augue, a suscipit justo
|
||||
sollicitudin eu. Interdum et malesuada fames ac ante ipsum primis in faucibus.
|
||||
Mauris scelerisque mi in risus mattis, posuere facilisis lacus rutrum. Integer
|
||||
a nisi sed ante molestie placerat. Ut eros dui, luctus vitae libero ultricies,
|
||||
sodales eleifend urna. Suspendisse potenti.
|
||||
|
||||
Phasellus tempus convallis posuere. In hac habitasse platea dictumst. Integer
|
||||
sit amet mi posuere, porta eros a, semper odio. Nunc mi lectus, pulvinar mollis
|
||||
enim non, posuere vestibulum enim. Donec luctus arcu sed felis imperdiet, non
|
||||
condimentum tellus viverra. Ut vestibulum ligula imperdiet, blandit lacus id,
|
||||
molestie sapien. Integer ultricies tortor a lacus egestas, a fermentum arcu
|
||||
aliquam. Vivamus quis diam eleifend, euismod nulla quis, consequat elit. Mauris
|
||||
sodales justo quis risus vehicula accumsan.
|
||||
|
||||
Aliquam fermentum dolor in sem bibendum bibendum. Sed sit amet augue malesuada,
|
||||
imperdiet augue eu, finibus risus. In vitae urna eros. Maecenas ex urna,
|
||||
lacinia sagittis tellus in, aliquam feugiat risus. Ut faucibus, nulla a
|
||||
pellentesque rhoncus, libero massa sodales mauris, vel dignissim ex est eu
|
||||
justo. Mauris libero nisl, varius vitae molestie sit amet, porta vitae justo.
|
||||
Pellentesque vel volutpat ante. Morbi ac elementum diam. Vestibulum ultricies
|
||||
fringilla laoreet. Nulla efficitur eros et quam rhoncus, in gravida lorem
|
||||
auctor. Integer quis mi elementum, dapibus nibh sed, tempus risus.
|
||||
|
||||
Fusce malesuada neque non nibh laoreet, id posuere quam mattis. Nulla volutpat
|
||||
mauris tortor, ac pellentesque ligula fermentum ut. Curabitur eu sem vel risus
|
||||
consequat dictum quis a elit. Praesent ultricies feugiat pretium. Nullam in
|
||||
congue metus, sed interdum est. Integer malesuada magna vitae lacus iaculis
|
||||
tincidunt. Ut volutpat euismod mi, eget placerat sapien sagittis sed. In
|
||||
vehicula neque id leo mollis, dapibus consequat justo venenatis. Donec aliquam
|
||||
augue sed finibus efficitur. Etiam molestie ligula bibendum felis volutpat
|
||||
malesuada. Sed molestie tempor nulla, at sollicitudin leo mattis vel. Sed a
|
||||
nunc porta, auctor est malesuada, suscipit velit. Phasellus euismod urna
|
||||
turpis, ut imperdiet ligula malesuada vel. Nullam iaculis vitae quam quis
|
||||
dignissim. Nam sit amet odio varius, pellentesque ex vel, finibus urna.
|
||||
|
||||
In lacinia semper fringilla. Proin ut turpis quis nunc ultricies suscipit in
|
||||
eget odio. Curabitur sodales et tortor et finibus. Suspendisse potenti.
|
||||
Phasellus augue arcu, pellentesque vel hendrerit quis, interdum at neque. Cras
|
||||
ornare, ante et ullamcorper commodo, dolor enim consectetur dolor, vel
|
||||
hendrerit orci arcu at nisl. Vestibulum tempus urna et purus aliquet
|
||||
scelerisque. Donec et mollis enim. Donec ipsum augue, condimentum et rhoncus
|
||||
sed, convallis sed velit. Maecenas faucibus, urna nec dictum tristique, augue
|
||||
diam pharetra nisi, vel imperdiet mi turpis vitae mauris. Fusce consequat massa
|
||||
eu libero efficitur, id imperdiet enim congue. Nullam volutpat scelerisque
|
||||
nulla, in tincidunt tellus finibus in.
|
||||
|
||||
Nam neque magna, venenatis ac dignissim vel, pretium in purus. Curabitur
|
||||
vestibulum feugiat dolor, vitae euismod justo tempor et. Nulla id lectus eget
|
||||
quam congue scelerisque. Ut eu aliquam lorem. Morbi non fringilla massa, vel
|
||||
faucibus quam. Sed posuere vehicula massa, ac laoreet magna gravida sed.
|
||||
Curabitur vitae volutpat metus, eu porta odio. Morbi id arcu ac est viverra
|
||||
blandit eget id dolor. Donec egestas ante vitae mattis placerat. Nulla iaculis
|
||||
erat in pharetra facilisis. Praesent efficitur eros ut lacus ornare aliquam a
|
||||
eu erat. Aenean placerat blandit mauris non congue.
|
||||
|
||||
Nulla fringilla id felis eu blandit. Integer suscipit sed nibh ut fringilla.
|
||||
Quisque lacinia porttitor erat vel fringilla. Phasellus varius, dui eu interdum
|
||||
mattis, lectus ipsum varius arcu, nec dignissim mi nisl ac mauris. Ut lacinia
|
||||
magna libero, fermentum ultrices nibh pharetra sit amet. Morbi tempus sed purus
|
||||
fringilla ultrices. In malesuada placerat dolor, dapibus viverra erat convallis
|
||||
placerat. Ut ultrices porta urna, a scelerisque dolor molestie in. Vivamus at
|
||||
odio quam. Integer suscipit id sem eu sodales. Nullam quis rhoncus nisl.
|
||||
|
||||
Maecenas eleifend venenatis purus facilisis facilisis. In molestie orci eu
|
||||
volutpat pretium. Curabitur quis est erat. Lorem ipsum dolor sit amet,
|
||||
consectetur adipiscing elit. Donec at dapibus nunc. Ut semper enim sagittis
|
||||
tellus imperdiet luctus. Morbi feugiat pellentesque scelerisque. Sed ac ex
|
||||
blandit, iaculis diam a, placerat ipsum. Quisque vitae lacinia ante, molestie
|
||||
consequat metus. Ut vitae fermentum erat. Proin vitae vehicula tellus. Maecenas
|
||||
aliquet malesuada lobortis. Maecenas eu mattis est. Etiam in quam eu lectus
|
||||
consequat varius.
|
||||
|
||||
Vestibulum nec leo nibh. Nulla cursus mauris eget rutrum sagittis. Morbi vel
|
||||
varius ligula. Donec ut vestibulum dolor. Integer maximus hendrerit erat, in
|
||||
varius dolor molestie non. Fusce non pellentesque ex, quis mollis metus. Nunc
|
||||
tempor, sapien ac tempus porttitor, erat neque fringilla nibh, vitae egestas
|
||||
massa arcu sed arcu. Morbi sollicitudin nisi nulla, eu pharetra massa finibus
|
||||
eget. Aliquam erat volutpat. Vivamus rutrum, nisl eu finibus vestibulum, sem
|
||||
tellus viverra ipsum, ullamcorper fermentum ligula lectus et mi. Aliquam ligula
|
||||
tortor, convallis sit amet ex ut, tempus tempor dui.
|
||||
|
||||
Nulla tempus, quam ac faucibus gravida, magna est interdum augue, ac fermentum
|
||||
odio arcu ut arcu. Quisque vel libero a sem posuere convallis. Quisque iaculis
|
||||
convallis imperdiet. Nulla a nisi quis ante tempus ultricies. Donec eu ante
|
||||
gravida, finibus lectus ac, viverra lacus. Nullam posuere blandit leo, eget
|
||||
euismod tellus egestas eu. Nunc quis mauris tortor. Donec molestie euismod leo,
|
||||
ut facilisis risus laoreet quis. Mauris metus nisi, semper non diam id,
|
||||
ullamcorper egestas libero. Aenean blandit mauris quam. Fusce vitae varius leo.
|
||||
Donec efficitur elit vel blandit dictum. Aenean molestie commodo enim. Fusce
|
||||
tempor luctus luctus.
|
||||
|
||||
Donec sit amet nibh sit amet arcu dignissim vulputate. Pellentesque ornare enim
|
||||
arcu, ac ullamcorper est hendrerit in. Duis sit amet ipsum bibendum, congue
|
||||
mauris in, tincidunt metus. Integer in lorem at nisi consectetur convallis id
|
||||
quis diam. Sed orci purus, euismod ut sem ut, sollicitudin maximus lacus. Sed
|
||||
pellentesque convallis arcu quis tincidunt. Donec mattis purus sodales risus
|
||||
mattis aliquet.
|
||||
|
||||
Nulla facilisi. Donec neque lectus, rhoncus at sagittis ut, bibendum non augue.
|
||||
Praesent posuere elit massa, eu porta justo aliquam non. Morbi sagittis lorem
|
||||
non lacus congue lobortis. Aliquam sodales augue nec leo ullamcorper feugiat.
|
||||
Quisque neque risus, porta viverra interdum id, tincidunt ut justo. Morbi
|
||||
dictum dui id magna faucibus, vel ultricies magna lobortis. Quisque lacinia leo
|
||||
quam, nec convallis ex egestas et. Integer vitae velit ex. Etiam ut vestibulum
|
||||
ipsum, in placerat mi. Vestibulum id blandit risus. Pellentesque eu mi
|
||||
pharetra, consectetur arcu imperdiet, viverra justo. Curabitur tempor, magna
|
||||
vitae laoreet maximus, metus eros maximus libero, quis scelerisque dolor tortor
|
||||
ac mauris. Maecenas placerat nisl tellus. Donec accumsan, eros eu efficitur
|
||||
convallis, turpis augue lacinia velit, in blandit libero diam a nulla. Quisque
|
||||
vitae felis eros.
|
||||
|
||||
Donec gravida pretium vulputate. Duis vestibulum pharetra ipsum non volutpat.
|
||||
Suspendisse volutpat, velit ut sodales porta, enim nulla fringilla magna, ac
|
||||
faucibus augue risus convallis ante. Duis pretium a eros eget tincidunt. In
|
||||
ligula risus, suscipit eu risus eget, fermentum pulvinar lectus. In aliquet
|
||||
quam nec aliquet accumsan. Mauris imperdiet, elit et tincidunt bibendum, ligula
|
||||
erat sollicitudin odio, vel semper augue diam ut magna. Donec vehicula, orci ac
|
||||
scelerisque eleifend, orci velit fermentum urna, id sagittis felis velit ac
|
||||
ipsum. Maecenas felis lacus, faucibus id tempor non, ultrices placerat elit.
|
||||
Nullam ante lorem, volutpat nec sagittis quis, luctus eget purus. Ut nec orci
|
||||
sem.
|
||||
|
||||
Curabitur condimentum condimentum metus eu elementum. Nunc pharetra nisi
|
||||
gravida ex consequat posuere. Nullam fermentum mauris in ex molestie fermentum.
|
||||
Sed neque neque, sodales ut turpis eu, porttitor tincidunt urna. Curabitur
|
||||
vehicula nibh ac mollis semper. Phasellus maximus nulla ut magna molestie
|
||||
rutrum eget et orci. Phasellus aliquet commodo nibh, ac pretium velit
|
||||
pellentesque et. Vestibulum ante ipsum primis in faucibus orci luctus et
|
||||
ultrices posuere cubilia curae; Sed eu mi fermentum, gravida tellus quis,
|
||||
hendrerit quam. Integer vel justo fermentum, dictum nibh eget, tincidunt dolor.
|
||||
Nunc nec tortor vel neque lacinia vulputate. In vitae ullamcorper neque, ut
|
||||
sollicitudin arcu. Nam sit amet egestas ligula. Pellentesque habitant morbi
|
||||
tristique senectus et netus et malesuada fames ac turpis egestas. Praesent
|
||||
scelerisque turpis at dolor placerat fringilla.
|
||||
|
||||
Praesent dignissim ligula et dignissim elementum. Fusce vel auctor enim. Etiam
|
||||
non lectus non erat ultricies porta sed rhoncus est. Morbi at posuere ligula.
|
||||
Morbi egestas ante quis porta pulvinar. Sed sit amet est felis. Proin ante
|
||||
eros, aliquam eu erat a, blandit tincidunt ante. Suspendisse sed lectus
|
||||
efficitur, molestie odio sit amet, convallis eros. Orci varius natoque
|
||||
penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin id
|
||||
ligula accumsan, consectetur tortor ac, facilisis justo. Nulla facilisi.
|
||||
Quisque sed quam fermentum, blandit magna at, consequat sapien. Interdum et
|
||||
malesuada fames ac ante ipsum primis in faucibus.
|
||||
|
||||
Sed vehicula vitae dui sed porttitor. Sed condimentum tortor justo, eget
|
||||
facilisis dolor euismod a. Proin commodo justo sed ultrices malesuada. Nulla
|
||||
eget risus aliquet, dignissim tortor vitae, rutrum erat. Quisque eleifend et
|
||||
metus non sagittis. Maecenas magna sapien, congue at tincidunt nec, eleifend
|
||||
sit amet sapien. Morbi vitae elementum mi. Duis at mauris nisi. Cras urna arcu,
|
||||
auctor in fringilla lobortis, porta vel elit. Donec sed velit eu felis varius
|
||||
rhoncus. Orci varius natoque penatibus et magnis dis parturient montes,
|
||||
nascetur ridiculus mus. Ut eget nisi nisl. Nullam vitae diam in diam ultrices
|
||||
tincidunt. Sed lacinia elit eu augue lacinia dictum. Aenean eu nisi volutpat,
|
||||
interdum velit vitae, ullamcorper urna.
|
||||
|
||||
Suspendisse ac est pulvinar, viverra nulla quis, varius sem. Praesent sit amet
|
||||
lacinia eros. Etiam consequat, quam a rutrum accumsan, lacus orci dictum justo,
|
||||
ut condimentum sem mi lobortis sem. Donec tempor lacus id laoreet ultricies.
|
||||
Duis quis lobortis lectus. Quisque rhoncus, ante ut aliquet sagittis, ligula
|
||||
metus molestie tellus, eget pretium risus risus ac augue. Ut nulla urna,
|
||||
gravida vel consequat at, condimentum ac sapien. Proin hendrerit purus mi, ut
|
||||
tristique diam suscipit a. Quisque nunc nisi, dignissim vel volutpat id,
|
||||
accumsan eu tortor. Sed nisl enim, faucibus ut dictum vel, eleifend ac massa.
|
||||
|
||||
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
|
||||
cubilia curae; Quisque venenatis quis nisl nec viverra. Vivamus a neque sit
|
||||
amet nisi viverra imperdiet. Curabitur congue sollicitudin erat, quis interdum
|
||||
urna molestie eget. Sed sit amet erat at lorem mollis malesuada. Pellentesque
|
||||
imperdiet pulvinar velit, in aliquet ipsum suscipit sit amet. Phasellus mollis
|
||||
ligula dolor, hendrerit gravida massa convallis vel. Nulla enim eros, dignissim
|
||||
id euismod sed, fringilla id justo. Ut a tristique lectus, quis viverra turpis.
|
||||
Proin at urna vel purus volutpat tristique a eu nisl. Etiam vitae libero
|
||||
fringilla, tristique lorem ac, luctus odio. Nam pharetra lorem vel porttitor
|
||||
porta. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
|
||||
cubilia curae; Sed blandit erat tincidunt, facilisis diam in, bibendum libero.
|
||||
Sed semper dui dapibus commodo bibendum.
|
||||
|
||||
Maecenas eleifend sapien magna, eget lobortis elit aliquet eu. Etiam laoreet
|
||||
sapien id leo tempus convallis. Donec molestie, elit non tincidunt eleifend,
|
||||
sem metus tincidunt erat, sed bibendum ipsum enim placerat arcu. Vestibulum
|
||||
fringilla dictum rhoncus. Mauris feugiat at lectus a lacinia. Donec et
|
||||
tincidunt lorem, in condimentum velit. Vivamus porttitor mi in nunc aliquam,
|
||||
vitae consequat mi pharetra. Vivamus laoreet eget felis sit amet vestibulum.
|
||||
|
||||
Donec rutrum volutpat mi, quis commodo ante tempus eu. Praesent sit amet nibh a
|
||||
ligula hendrerit vehicula. Sed pellentesque a nulla ut fringilla. Phasellus id
|
||||
tortor metus. Vestibulum sit amet blandit odio, non gravida dui. Donec auctor
|
||||
feugiat viverra. Mauris vel blandit lorem.
|
||||
|
||||
Suspendisse viverra gravida nisl, quis tempor nisl consequat eu. Aliquam
|
||||
finibus eros lobortis lectus varius sagittis quis non velit. Integer tincidunt
|
||||
elit felis, a auctor arcu cursus placerat. In a nunc elit. Suspendisse
|
||||
tristique turpis est, quis iaculis nisl interdum vel. Quisque elit nulla,
|
||||
lacinia nec est vel, porttitor ullamcorper lorem. Suspendisse at sem ornare,
|
||||
ultrices mauris vitae, iaculis quam. Suspendisse vitae tellus dictum,
|
||||
consectetur dui vitae, porttitor ipsum. Pellentesque quis tellus dolor.
|
||||
Pellentesque in tincidunt odio. Proin a molestie ipsum, eget viverra purus.
|
||||
Nulla facilisi. Pellentesque lacinia sollicitudin lacus eget imperdiet. In
|
||||
volutpat tortor mi. Aliquam tincidunt placerat risus, sit amet sagittis nisi
|
||||
mattis dictum.
|
||||
|
||||
Mauris sed est laoreet augue finibus feugiat. Aliquam vehicula molestie enim,
|
||||
in blandit enim scelerisque sit amet. Vestibulum consequat massa ex, nec
|
||||
lacinia nisl ultricies vel. Aliquam erat volutpat. Proin rhoncus euismod
|
||||
feugiat. Sed tincidunt augue odio, ac auctor justo consequat ut. Nulla
|
||||
fermentum metus sollicitudin leo rutrum, non pulvinar turpis elementum. Quisque
|
||||
lorem turpis, accumsan nec dapibus ut, aliquam ut lorem.
|
||||
|
||||
Morbi a imperdiet quam. Aliquam euismod tincidunt lorem ac gravida. Lorem ipsum
|
||||
dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet,
|
||||
consectetur adipiscing elit. Aliquam eu sagittis orci. Nulla ac varius eros, id
|
||||
elementum ante. Etiam aliquam sem sed metus eleifend maximus. Phasellus eu
|
||||
gravida risus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices
|
||||
posuere cubilia curae; Nullam velit mauris, tempor ut malesuada sollicitudin,
|
||||
gravida eget magna. Phasellus aliquam mollis risus ac rutrum. Donec vulputate
|
||||
ligula sed purus vestibulum mattis quis at orci. Morbi vel consectetur magna.
|
||||
|
||||
Pellentesque eget ligula sed magna vehicula blandit sed at ex. Nullam aliquet
|
||||
vel turpis vel varius. Vestibulum sit amet varius neque. Phasellus sem enim,
|
||||
varius ut consectetur sed, pulvinar et velit. Cras a porta mi, ut feugiat elit.
|
||||
Sed commodo libero eu enim consectetur, nec maximus quam consequat. Vestibulum
|
||||
in ante facilisis, iaculis eros sit amet, finibus magna. Sed ullamcorper
|
||||
eleifend dui eu congue. Phasellus vel tellus a lectus aliquet dapibus. Ut
|
||||
congue, magna vel fringilla mattis, leo dolor convallis metus, a ullamcorper
|
||||
ipsum neque sed dolor. Ut quis egestas dui. Vestibulum nec egestas dolor.
|
||||
|
||||
Curabitur dictum orci augue. Sed tortor risus, porta vitae sodales ac, aliquam
|
||||
eget ex. Proin accumsan non lacus eget placerat. Orci varius natoque penatibus
|
||||
et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque malesuada
|
||||
ornare sem id tincidunt. Vivamus ac vestibulum dui. Phasellus vel laoreet dui.
|
||||
Aliquam vulputate est vel neque egestas, at fermentum lectus consectetur.
|
||||
Integer mollis turpis nunc, condimentum placerat justo sodales sed.
|
||||
|
||||
Nunc ullamcorper malesuada elit sed convallis. Nulla malesuada sapien facilisis
|
||||
orci vulputate, feugiat gravida felis commodo. Suspendisse lacinia tempus
|
||||
elementum. Suspendisse aliquet id ex vel commodo. Praesent iaculis neque congue
|
||||
ullamcorper consequat. Etiam ut tellus vel libero ullamcorper commodo. Ut
|
||||
dignissim enim ac laoreet gravida. Duis vitae dictum ex. Morbi mattis tellus et
|
||||
laoreet congue.
|
||||
|
||||
Nam elementum at magna tincidunt ornare. Quisque rutrum interdum eros eget
|
||||
feugiat. Donec lacinia ornare ultricies. Etiam sollicitudin blandit sapien
|
||||
placerat laoreet. Morbi sed urna in libero egestas faucibus. In id sem eu sem
|
||||
tempus euismod. Sed orci nulla, finibus vel lorem vel, luctus feugiat nibh.
|
||||
Integer at pellentesque est. Aliquam dapibus, enim in convallis tempor, orci
|
||||
ante posuere odio, id rutrum mauris lorem id lectus. Sed suscipit, neque quis
|
||||
aliquam gravida, mi velit porttitor tortor, id luctus velit mauris ut turpis.
|
||||
Nullam quis egestas lorem. Nam et varius mauris, dictum varius elit. Nullam nec
|
||||
orci non lorem posuere sodales nec eu odio. Phasellus nec consectetur lectus.
|
||||
|
||||
Nulla tempor imperdiet neque, quis auctor felis malesuada euismod. Nullam
|
||||
imperdiet ante non dignissim sodales. Quisque sed egestas ante. Phasellus vitae
|
||||
lorem nisl. Quisque malesuada elementum sem. Quisque ligula velit, aliquam sed
|
||||
hendrerit a, hendrerit in lectus. Nulla non volutpat est, vitae condimentum
|
||||
risus. Integer accumsan rutrum lacus, ac tempus mauris tincidunt vitae.
|
||||
Suspendisse gravida in ex vel rutrum. Curabitur nec sagittis nulla. Quisque
|
||||
tincidunt malesuada augue vitae condimentum. Suspendisse eu leo ac dolor
|
||||
posuere ultricies quis ac metus. Sed porta, dui quis fringilla facilisis, ante
|
||||
velit posuere turpis, nec gravida purus lectus eget odio. Proin id bibendum
|
||||
justo. Proin sapien est, varius tempus libero a, consequat iaculis ipsum.
|
||||
|
||||
Curabitur ut nisi quis lectus vehicula pretium ut at tellus. Quisque consequat
|
||||
eget enim sed eleifend. In at interdum metus. Vestibulum ante ipsum primis in
|
||||
faucibus orci luctus et ultrices posuere cubilia curae; Integer porta nibh a
|
||||
dictum tempus. Mauris interdum libero quam, id venenatis nibh tempus in. Nulla
|
||||
ornare blandit dui, nec facilisis eros tempor quis. Curabitur euismod lobortis
|
||||
condimentum. Nam convallis odio vitae dui porttitor, in hendrerit eros
|
||||
bibendum. Proin convallis, sapien a convallis vulputate, felis nulla iaculis
|
||||
purus, in mollis neque nulla non odio. Nullam non tellus varius, blandit ante
|
||||
sed, venenatis enim. Vivamus aliquam risus quis risus aliquet, id vestibulum
|
||||
felis eleifend. Praesent a felis a odio bibendum tincidunt. Sed odio nisl,
|
||||
laoreet nec nunc in, suscipit accumsan tellus. Nulla vitae lorem eu orci
|
||||
bibendum mattis id quis nisi. Mauris a purus libero.
|
||||
|
||||
Curabitur non sapien efficitur, egestas orci at, imperdiet neque. Vestibulum
|
||||
condimentum mauris tellus, eget mollis sapien vulputate quis. Ut ac lectus
|
||||
enim. Cras ut convallis nisl. Proin sed porta elit. Nam posuere tellus nec
|
||||
massa scelerisque, at facilisis nibh vulputate. Mauris dictum neque iaculis
|
||||
quam elementum, posuere lacinia libero egestas. Nulla sapien risus, vestibulum
|
||||
fermentum tincidunt non, placerat in orci. Sed eu ipsum nisi. Aliquam eget
|
||||
felis felis. Donec non nisi vel nunc luctus vehicula quis at tellus. Mauris
|
||||
tincidunt nulla sit amet lorem sodales imperdiet. Suspendisse ac enim a enim
|
||||
tincidunt fermentum quis ornare lacus. Phasellus ac nunc vitae libero fermentum
|
||||
ultricies. Praesent suscipit ligula metus, et lobortis mauris varius vel.
|
||||
|
||||
Maecenas lectus tortor, dignissim malesuada blandit in, iaculis ac tellus.
|
||||
Nulla vel sollicitudin lectus, eget pellentesque massa. Nam ac bibendum ligula.
|
||||
Phasellus molestie nec dui vel accumsan. Nam sit amet tempor diam. In vulputate
|
||||
aliquam nisl et aliquam. Donec feugiat fringilla turpis sit amet gravida.
|
||||
Pellentesque consectetur erat quis neque gravida gravida. Fusce blandit vitae
|
||||
tellus quis malesuada. Mauris volutpat interdum ligula nec dapibus. Class
|
||||
aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos
|
||||
himenaeos.
|
||||
|
||||
Vivamus in odio purus. Nam blandit dolor ut dolor mollis dapibus. Quisque
|
||||
posuere ullamcorper tortor ac pharetra. Sed eget sagittis purus. Donec ut augue
|
||||
ac nisi accumsan tempus. Aliquam at neque nec lacus aliquam tempor. Mauris et
|
||||
purus quis odio bibendum porta sed eget arcu. Curabitur mauris nisl, semper id
|
||||
facilisis et, convallis nec diam. Orci varius natoque penatibus et magnis dis
|
||||
parturient montes, nascetur ridiculus mus. Aliquam erat volutpat. Vestibulum
|
||||
accumsan lobortis orci, accumsan bibendum dui facilisis nec. Donec at nisi non
|
||||
nulla facilisis dictum. Phasellus sit amet nisi ornare, posuere nisi ac,
|
||||
egestas nulla. Nam gravida vel quam quis pharetra.
|
||||
|
||||
Nulla pharetra dignissim mauris, ut finibus nunc volutpat eget. Donec mattis
|
||||
lobortis porta. Sed consequat magna turpis, dapibus pretium odio euismod nec.
|
||||
Nunc ultricies volutpat imperdiet. In posuere nisi et purus ullamcorper
|
||||
sagittis. Sed ligula turpis, lobortis nec vulputate id, luctus in lorem.
|
||||
Curabitur consectetur vel mauris vitae malesuada. Phasellus vestibulum dapibus
|
||||
urna, in rutrum neque porttitor ut. Pellentesque sodales pellentesque aliquet.
|
||||
Maecenas dapibus dignissim metus, quis dignissim magna.
|
||||
|
||||
Quisque id ante commodo, porttitor nibh venenatis, pharetra purus. Duis viverra
|
||||
at libero non gravida. Aenean dictum sit amet sem at malesuada. Integer vitae
|
||||
quam a ante dictum condimentum nec nec felis. Donec et suscipit massa, et
|
||||
vulputate ex. Integer eget libero nec felis facilisis cursus nec sit amet nisi.
|
||||
Nullam facilisis, quam sit amet dictum luctus, erat mauris accumsan risus, ac
|
||||
commodo enim eros ut augue. Curabitur at dolor tortor. Suspendisse tincidunt
|
||||
malesuada volutpat.
|
||||
|
||||
Pellentesque non purus in turpis accumsan euismod sit amet in lacus. Vestibulum
|
||||
ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae;
|
||||
Morbi consectetur volutpat ultricies. Donec lacus mauris, euismod sed nunc in,
|
||||
ultricies vehicula dui. Praesent a enim quis tortor fermentum mollis at non
|
||||
lorem. Suspendisse potenti. Sed non commodo enim. Vivamus a odio urna. Donec ac
|
||||
orci est. Sed tincidunt metus nulla, at placerat lectus pharetra et.
|
||||
|
||||
Suspendisse ac ex nibh. Praesent id bibendum eros, sit amet semper tortor.
|
||||
Aliquam a dolor at eros gravida consequat quis tincidunt libero. Morbi a nisl
|
||||
id augue viverra consectetur ac scelerisque dui. Morbi nec tellus quam. In
|
||||
cursus augue nec mattis pellentesque. Aliquam erat volutpat. Phasellus vehicula
|
||||
lorem consectetur leo molestie, fringilla ornare tortor interdum. Duis quis
|
||||
sodales magna, at mollis risus. Proin venenatis purus sed urna pretium, vel
|
||||
eleifend arcu condimentum. Maecenas maximus placerat purus, in molestie turpis
|
||||
consectetur in. Aliquam a arcu gravida, condimentum elit vel, vulputate dolor.
|
||||
Duis vel justo ac velit bibendum ullamcorper. Suspendisse vestibulum mollis
|
||||
libero eu fringilla. Vestibulum vel velit pretium, congue nisi id, viverra
|
||||
sapien.
|
||||
|
||||
Cras consectetur tellus quis tellus posuere sodales. Pellentesque habitant
|
||||
morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aenean
|
||||
at congue mauris. Duis eget nulla vitae neque tempor fermentum a vitae enim.
|
||||
Aliquam volutpat massa et lorem porttitor, eget sagittis libero tristique.
|
||||
Fusce vel leo id elit fringilla mattis. Curabitur vitae ligula urna. Mauris
|
||||
varius rutrum varius. Phasellus facilisis ipsum sed dui condimentum, at varius
|
||||
justo elementum. Maecenas vehicula justo a cursus mattis. Nullam id enim nisl.
|
||||
Pellentesque dapibus erat nunc, vitae tempor sapien blandit et. Donec pretium
|
||||
dui in risus vehicula dapibus. Cras feugiat facilisis placerat. Curabitur quis
|
||||
odio sed mi maximus auctor ac ac elit.
|
||||
|
||||
Aenean sit amet neque ligula. Aliquam et risus ac arcu egestas dictum. Quisque
|
||||
varius efficitur enim, aliquet vehicula sem euismod ac. Vestibulum ac efficitur
|
||||
erat. Ut elementum, purus non tristique molestie, eros dui cursus est, eu
|
||||
ultricies tortor lorem id quam. Etiam volutpat euismod velit, ut posuere dolor
|
||||
tempor quis. Vivamus venenatis neque sed ante sodales pharetra. Nam nec lectus
|
||||
urna. Etiam ultricies venenatis metus vitae hendrerit. Integer massa nunc,
|
||||
auctor ut luctus ac, dignissim vel mauris. Nullam sollicitudin laoreet justo
|
||||
vel pretium. Nam blandit mauris a mauris porttitor, sed cursus risus posuere.
|
||||
Nam consequat venenatis consectetur. Duis non porta tortor. Nullam bibendum
|
||||
lorem in fringilla eleifend.
|
||||
|
||||
Ut sed urna ipsum. Pellentesque vestibulum, augue quis vulputate rutrum, nulla
|
||||
ipsum imperdiet diam, viverra volutpat ligula leo eu mi. Phasellus accumsan
|
||||
risus in augue tincidunt laoreet. Proin bibendum nunc ut vulputate porttitor.
|
||||
Vestibulum laoreet malesuada pharetra. Sed in gravida augue. Nunc hendrerit id
|
||||
urna in iaculis. Morbi fringilla hendrerit orci, vitae gravida felis ultrices
|
||||
quis. Integer id commodo eros. Maecenas eu augue nec purus tristique dapibus.
|
||||
Aenean metus diam, vehicula id mauris sit amet, iaculis sollicitudin dui.
|
||||
|
||||
Suspendisse neque dui, pharetra eu accumsan a, interdum et metus. Proin et
|
||||
lacus eget purus sagittis tempor at eu dolor. Nullam eget auctor velit. Sed
|
||||
vitae venenatis nulla, ut dignissim magna. Proin euismod et arcu eu suscipit.
|
||||
Curabitur sit amet congue lorem. Nullam tincidunt nisl sit amet odio dignissim,
|
||||
nec vulputate leo lobortis. Pellentesque habitant morbi tristique senectus et
|
||||
netus et malesuada fames ac turpis egestas. Ut congue ipsum sem, et rhoncus
|
||||
neque interdum nec. Curabitur in eros ullamcorper, facilisis leo auctor,
|
||||
vestibulum nisl. Curabitur eu odio eros. Fusce fermentum ornare augue non
|
||||
luctus. Nunc eget purus in eros euismod fermentum. Praesent interdum neque sed
|
||||
mi gravida, vel condimentum est efficitur. Ut a nulla non lectus pellentesque
|
||||
pretium.
|
||||
|
||||
Mauris dictum odio consequat iaculis dapibus. Fusce porttitor, nulla non semper
|
||||
ultricies, lectus mauris lacinia quam, id dapibus metus metus eu neque.
|
||||
Maecenas commodo, velit sed hendrerit imperdiet, ex turpis tincidunt nisi,
|
||||
vitae accumsan ipsum lorem id dui. Pellentesque nec ipsum neque. Ut sed quam
|
||||
auctor, fermentum lorem tincidunt, aliquam ligula. Ut vulputate nibh id ligula
|
||||
aliquam aliquet. Donec egestas libero a augue convallis commodo. Sed commodo
|
||||
ligula aliquet dictum aliquam. Integer pulvinar urna ac sapien scelerisque
|
||||
mattis. Curabitur maximus ultricies nisi, sed tristique lacus tincidunt vitae.
|
||||
Fusce tempus magna egestas interdum molestie.
|
||||
|
||||
Quisque nec molestie libero. Aliquam erat volutpat. Praesent sagittis tortor
|
||||
ante, vel laoreet dui fermentum in. Aliquam a leo ut arcu egestas posuere. Nam
|
||||
sit amet ex pulvinar, dapibus mi nec, malesuada velit. Phasellus dignissim
|
||||
sapien nulla, sit amet aliquam turpis iaculis quis. Nulla vel metus id mauris
|
||||
eleifend aliquam. Phasellus et risus purus. Vivamus lobortis lorem non libero
|
||||
semper, et lacinia diam accumsan.
|
||||
|
||||
Ut eu molestie ante. Nunc a varius neque, non sollicitudin nisi. Nullam et
|
||||
fringilla libero. Fusce turpis lacus, aliquam non dui ac, laoreet condimentum
|
||||
magna. Integer scelerisque risus non lectus porttitor cursus. Duis porta cursus
|
||||
turpis, vitae laoreet justo mattis a. Donec ac orci odio. Aliquam pulvinar
|
||||
dictum ex. Vivamus ut ipsum nec sapien venenatis pulvinar. Nullam pulvinar
|
||||
porttitor libero, et luctus quam tincidunt sed. Aenean id efficitur dolor.
|
||||
Curabitur nisi dolor, mollis ac elit sed, sodales viverra ante. Nulla eget
|
||||
malesuada sapien. Aliquam eu erat ac lorem laoreet sagittis.
|
||||
|
||||
Nam commodo leo libero, eu faucibus eros maximus in. Nunc efficitur suscipit mi
|
||||
quis rutrum. Sed non ligula odio. Maecenas tempus erat urna, nec mattis sapien
|
||||
ullamcorper eget. Ut massa mauris, cursus quis nulla et, rutrum pharetra arcu.
|
||||
Morbi erat urna, dapibus ac odio in, tincidunt aliquam odio. Proin quis justo
|
||||
et nisi cursus maximus. Maecenas eu ornare dui. Sed nec vulputate justo. Etiam
|
||||
dapibus sed metus vitae consequat. In at pharetra arcu. Duis id massa mauris.
|
||||
|
||||
Integer accumsan orci a congue laoreet. Morbi auctor pulvinar pellentesque.
|
||||
Praesent sollicitudin enim risus, non tristique sapien hendrerit quis. Donec
|
||||
eget tempus est, sed ultrices ex. Maecenas ut turpis placerat, faucibus magna
|
||||
a, dapibus nisl. Donec vitae est eu leo interdum placerat nec sodales nulla. In
|
||||
lobortis egestas enim, ac pretium enim blandit in. Nullam efficitur justo id
|
||||
magna accumsan egestas. Proin non neque nec libero dapibus tincidunt. Duis eget
|
||||
tristique libero. Nam in lobortis ligula. Donec fermentum metus in enim
|
||||
pharetra malesuada.
|
||||
|
||||
Nunc interdum, orci ac luctus viverra, turpis nunc tempus purus, dignissim
|
||||
tempus turpis mauris ac diam. Pellentesque ut urna enim. In dui sapien, euismod
|
||||
et sagittis et, posuere vitae quam. Sed sit amet nulla turpis. Nullam non
|
||||
aliquam enim, eget tempor nulla. Aliquam tincidunt hendrerit tellus sit amet
|
||||
porttitor. Integer erat lorem, ultrices quis semper eget, rutrum id nisl. Cras
|
||||
porttitor felis vitae lorem tristique semper. Aenean maximus lectus libero, ac
|
||||
fermentum tortor consequat ac. Integer cursus augue nec tellus molestie, vitae
|
||||
ornare massa ultrices. Duis luctus dignissim porttitor. Sed eu lobortis neque.
|
||||
Aenean dapibus laoreet congue. Integer vitae viverra sem.
|
||||
|
||||
Mauris velit lectus, blandit at auctor non, porttitor dapibus velit. Phasellus
|
||||
egestas volutpat lectus, in sodales lacus cursus vitae. Fusce lectus sapien,
|
||||
blandit in elit sit amet, rhoncus dignissim turpis. Donec ut ex dictum, auctor
|
||||
ex varius, maximus ligula. Fusce mattis pharetra eros, sit amet tincidunt ante
|
||||
sollicitudin sit amet. Duis eros metus, congue id massa sit amet, lobortis
|
||||
malesuada lectus. Pellentesque sagittis urna et imperdiet feugiat. Sed at nisl
|
||||
vitae lectus laoreet malesuada ut a leo. Sed rhoncus ex sit amet erat luctus
|
||||
bibendum. Quisque bibendum purus ultricies ligula tincidunt lobortis.
|
||||
Vestibulum orci erat, euismod sed felis non, sagittis ultrices purus. Donec
|
||||
faucibus dolor est, vitae ornare nulla congue ac. Duis ac ultrices massa, id
|
||||
facilisis turpis. Curabitur luctus lorem sed justo imperdiet aliquam. Quisque a
|
||||
ultricies quam. Nam scelerisque eu felis id dictum.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec molestie tempus
|
||||
justo eget vulputate. Praesent fermentum metus ex, ac convallis ipsum egestas
|
||||
et. Phasellus vel placerat metus. Nulla facilisi. Mauris pretium risus in
|
||||
sodales convallis. Vestibulum rutrum rutrum nibh, nec gravida nisl gravida eu.
|
||||
Sed imperdiet at urna a tincidunt. Curabitur sed diam aliquet, consectetur
|
||||
metus ac, placerat tellus. Quisque vel dignissim nisi. Donec vitae elit risus.
|
||||
|
||||
Phasellus ullamcorper, libero sit amet tincidunt placerat, neque arcu tincidunt
|
||||
orci, eu pulvinar orci dui in diam. Integer lacinia vestibulum feugiat. Sed a
|
||||
luctus enim. Aenean eu augue est. Vivamus molestie, arcu eu bibendum
|
||||
vestibulum, est lorem volutpat leo, vel euismod leo nibh nec ipsum. Integer
|
||||
magna leo, tempus eu consectetur vitae, tristique ultrices lectus. Curabitur
|
||||
elit turpis, convallis et eros a, condimentum condimentum metus. Lorem ipsum
|
||||
dolor sit amet, consectetur adipiscing elit. Maecenas vulputate lacus at mattis
|
||||
facilisis.
|
||||
|
||||
Ut diam mi, facilisis vel augue nec, luctus consectetur augue. Nulla non
|
||||
pellentesque nulla. Integer vel porta augue. Nullam tincidunt sit amet nisi id
|
||||
mollis. Nulla fringilla nunc in metus vulputate, sit amet gravida nisi cursus.
|
||||
Mauris posuere elementum metus, ut molestie felis consectetur a. Nullam vitae
|
||||
euismod velit, sit amet ultricies elit. Ut auctor orci felis, tempor feugiat
|
||||
felis elementum facilisis. Pellentesque vehicula non lectus in dapibus. Nam sit
|
||||
amet tincidunt felis. Pellentesque ac dui eu ipsum viverra placerat non a odio.
|
||||
Sed sit amet vestibulum nisi, et sodales mauris. Nam vestibulum feugiat
|
||||
interdum.
|
||||
|
||||
Maecenas feugiat a elit sit amet lacinia. Fusce tristique felis vel elit
|
||||
pharetra, et vestibulum arcu pellentesque. Proin commodo egestas risus, eget
|
||||
tincidunt turpis pharetra eget. Maecenas tincidunt ipsum ultrices erat
|
||||
vestibulum suscipit. Etiam aliquet risus at ante maximus suscipit. Ut non
|
||||
faucibus diam, a dapibus est. Proin egestas, leo et malesuada tincidunt, quam
|
||||
erat commodo ex, ut convallis tellus ex ac massa. Aenean maximus laoreet magna.
|
||||
In ut nibh placerat nisl aliquam fermentum et et quam. Aenean varius libero sit
|
||||
amet aliquet fermentum. Proin et velit eget nulla dignissim tristique.
|
||||
|
||||
Vivamus malesuada, mauris in tincidunt congue, sem sapien efficitur mi, in
|
||||
elementum enim est a diam. Nulla in tincidunt diam, molestie mollis risus. In
|
||||
pharetra iaculis erat, ac semper diam condimentum vitae. Morbi ante neque,
|
||||
sollicitudin eget mauris sit amet, eleifend mattis mi. Curabitur blandit nunc
|
||||
sapien, at rhoncus sem ultricies non. Quisque a tristique magna. Praesent
|
||||
eleifend, lorem nec blandit commodo, mi nisi tincidunt metus, cursus aliquam
|
||||
eros lectus vel dui. Mauris blandit congue tortor et consectetur. Etiam vitae
|
||||
sem commodo, auctor est elementum, tempus urna.
|
||||
|
||||
Vivamus gravida luctus scelerisque. Praesent non scelerisque erat. Pellentesque
|
||||
fermentum tellus sapien, et viverra odio sollicitudin ac. Etiam accumsan odio
|
||||
metus, et dictum nulla pharetra sed. Ut eu vulputate quam. Orci varius natoque
|
||||
penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi at
|
||||
molestie justo. Ut mattis porta tempor. Nunc commodo est ac felis tempor, quis
|
||||
lobortis mauris commodo. Nullam id accumsan nulla. Nullam in nulla mauris. Sed
|
||||
euismod tortor eget tempus venenatis. Suspendisse consequat pellentesque enim.
|
||||
|
||||
Nunc nulla ligula, volutpat ut consequat eget, dignissim vitae mi. Etiam sit
|
||||
amet justo nec justo lacinia malesuada eget at diam. Nunc consequat libero
|
||||
eleifend, consequat ex ac, tincidunt turpis. Morbi faucibus quam et ante
|
||||
efficitur, dignissim ullamcorper orci finibus. Phasellus vel convallis orci.
|
||||
Donec ultricies, odio eu tristique accumsan, turpis risus malesuada metus, in
|
||||
mattis elit ligula nec metus. Sed ac eros velit. Pellentesque rutrum sagittis
|
||||
finibus. Nullam cursus interdum est, sit amet maximus est posuere eu. Integer
|
||||
tempor justo non tellus volutpat, at vulputate urna malesuada. Vestibulum eget
|
||||
eros quis erat sollicitudin finibus. Aenean in sem eget ipsum sodales
|
||||
hendrerit. Praesent sit amet egestas lorem, vel bibendum nulla. Nullam ac
|
||||
malesuada lacus.
|
||||
|
||||
Nullam massa lacus, lobortis vel vulputate in, venenatis id arcu. Sed eu libero
|
||||
elit. Suspendisse metus metus, lobortis quis congue in, imperdiet vel est.
|
||||
Phasellus elit leo, rutrum eget augue vel, vestibulum feugiat mi. Nullam nisl
|
||||
arcu, interdum vitae lorem nec, accumsan viverra leo. Proin massa magna,
|
||||
volutpat vitae dapibus et, porta in lectus. Aliquam venenatis enim ex, ac
|
||||
consectetur ligula porttitor sed. Curabitur vel justo eros. Aliquam at id.
|
||||
`
|
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package tar
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
arcmod "github.com/nabbar/golib/archive/archive"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
const pkgName = "golib/archive/tar"
|
||||
|
||||
const (
|
||||
ErrorParamEmpty liberr.CodeError = iota + arcmod.MinPkgArchiveTar
|
||||
ErrorTarNext
|
||||
ErrorFileOpen
|
||||
ErrorFileSeek
|
||||
ErrorFileClose
|
||||
ErrorIOCopy
|
||||
ErrorDirCreate
|
||||
ErrorLinkCreate
|
||||
ErrorSymLinkCreate
|
||||
ErrorDestinationStat
|
||||
ErrorDestinationIsDir
|
||||
ErrorDestinationIsNotDir
|
||||
ErrorDestinationRemove
|
||||
ErrorTarCreate
|
||||
ErrorGzipCreate
|
||||
ErrorTarCreateAddFile
|
||||
)
|
||||
|
||||
func init() {
|
||||
if liberr.ExistInMapMessage(ErrorParamEmpty) {
|
||||
panic(fmt.Errorf("error code collision %s", pkgName))
|
||||
}
|
||||
liberr.RegisterIdFctMessage(ErrorParamEmpty, getMessage)
|
||||
}
|
||||
|
||||
func getMessage(code liberr.CodeError) (message string) {
|
||||
switch code {
|
||||
case liberr.UnknownError:
|
||||
return liberr.NullMessage
|
||||
case ErrorParamEmpty:
|
||||
return "given parameters is empty"
|
||||
case ErrorTarNext:
|
||||
return "cannot get next tar file"
|
||||
case ErrorFileSeek:
|
||||
return "cannot seek into file"
|
||||
case ErrorFileOpen:
|
||||
return "cannot open file"
|
||||
case ErrorFileClose:
|
||||
return "closing file occurs error"
|
||||
case ErrorIOCopy:
|
||||
return "io copy occurs error"
|
||||
case ErrorDirCreate:
|
||||
return "make directory occurs error"
|
||||
case ErrorLinkCreate:
|
||||
return "creation of symlink occurs error"
|
||||
case ErrorSymLinkCreate:
|
||||
return "creation of symlink occurs error"
|
||||
case ErrorDestinationStat:
|
||||
return "cannot stat destination"
|
||||
case ErrorDestinationIsDir:
|
||||
return "cannot create destination not directory over an existing directory"
|
||||
case ErrorDestinationIsNotDir:
|
||||
return "cannot create destination directory over an existing non directory"
|
||||
case ErrorDestinationRemove:
|
||||
return "cannot remove destination "
|
||||
case ErrorTarCreate:
|
||||
return "cannot create Tar archive"
|
||||
case ErrorGzipCreate:
|
||||
return "cannot create Gzip compression for the Tar archive"
|
||||
case ErrorTarCreateAddFile:
|
||||
return "cannot add file content to tar archive"
|
||||
}
|
||||
|
||||
return liberr.NullMessage
|
||||
}
|
@@ -1,237 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package tar
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
libarc "github.com/nabbar/golib/archive/archive"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
libfpg "github.com/nabbar/golib/file/progress"
|
||||
)
|
||||
|
||||
func GetFile(src, dst libfpg.Progress, filenameContain, filenameRegex string) liberr.Error {
|
||||
|
||||
if _, e := src.Seek(0, io.SeekStart); e != nil {
|
||||
return ErrorFileSeek.Error(e)
|
||||
} else if _, e = dst.Seek(0, io.SeekStart); e != nil {
|
||||
return ErrorFileSeek.Error(e)
|
||||
}
|
||||
|
||||
r := tar.NewReader(src)
|
||||
|
||||
for {
|
||||
h, e := r.Next()
|
||||
if e != nil && e == io.EOF {
|
||||
return nil
|
||||
} else if e != nil {
|
||||
return ErrorTarNext.Error(e)
|
||||
}
|
||||
|
||||
if h.FileInfo().Mode()&os.ModeType == os.ModeType {
|
||||
continue
|
||||
}
|
||||
|
||||
f := libarc.NewFileFullPath(h.Name)
|
||||
|
||||
//nolint #nosec
|
||||
/* #nosec */
|
||||
if f.MatchingFullPath(filenameContain) || f.RegexFullPath(filenameRegex) {
|
||||
if _, e = dst.ReadFrom(r); e != nil {
|
||||
return ErrorIOCopy.Error(e)
|
||||
} else if _, e = dst.Seek(0, io.SeekStart); e != nil {
|
||||
return ErrorFileSeek.Error(e)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetAll(src io.ReadSeeker, outputFolder string, defaultDirPerm os.FileMode) liberr.Error {
|
||||
|
||||
if _, e := src.Seek(0, io.SeekStart); e != nil {
|
||||
return ErrorFileSeek.Error(e)
|
||||
}
|
||||
|
||||
r := tar.NewReader(src)
|
||||
|
||||
for {
|
||||
h, e := r.Next()
|
||||
if e != nil && e == io.EOF {
|
||||
return nil
|
||||
} else if e != nil {
|
||||
return ErrorTarNext.Error(e)
|
||||
}
|
||||
|
||||
dst := filepath.Join(outputFolder, libarc.CleanPath(strings.Replace(h.Name, ".."+string(filepath.Separator), "", -1)))
|
||||
|
||||
//nolint #nosec
|
||||
/* #nosec */
|
||||
if err := writeContent(r, h, dst, defaultDirPerm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func writeContent(r io.Reader, h *tar.Header, out string, defaultDirPerm os.FileMode) (err liberr.Error) {
|
||||
var (
|
||||
e error
|
||||
|
||||
inf = h.FileInfo()
|
||||
dst libfpg.Progress
|
||||
)
|
||||
|
||||
if e := dirIsExistOrCreate(filepath.Dir(out), defaultDirPerm); e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if dst != nil {
|
||||
if e := dst.Close(); e != nil {
|
||||
err = ErrorFileClose.Error(e)
|
||||
err.Add(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if h.Typeflag&tar.TypeDir == tar.TypeDir {
|
||||
err = dirIsExistOrCreate(out, h.FileInfo().Mode())
|
||||
return
|
||||
} else if err = notDirExistCannotClean(out, h.Typeflag, h.Linkname); err != nil {
|
||||
return
|
||||
} else if h.Typeflag&tar.TypeLink == tar.TypeLink {
|
||||
return createLink(out, libarc.CleanPath(h.Linkname), false)
|
||||
} else if h.Typeflag&tar.TypeSymlink == tar.TypeSymlink {
|
||||
return createLink(out, libarc.CleanPath(h.Linkname), true)
|
||||
}
|
||||
|
||||
if dst, e = libfpg.New(out, os.O_RDWR|os.O_CREATE|os.O_TRUNC, inf.Mode()); e != nil {
|
||||
return ErrorFileOpen.Error(e)
|
||||
} else if _, e = io.Copy(dst, r); e != nil {
|
||||
return ErrorIOCopy.Error(e)
|
||||
} else if e = dst.Close(); e != nil {
|
||||
return ErrorFileClose.Error(e)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func dirIsExistOrCreate(dirname string, dirPerm os.FileMode) liberr.Error {
|
||||
if i, e := os.Stat(dirname); e != nil && os.IsNotExist(e) {
|
||||
if e = os.MkdirAll(dirname, dirPerm); e != nil {
|
||||
return ErrorDirCreate.Error(e)
|
||||
}
|
||||
} else if e != nil {
|
||||
return ErrorDestinationStat.Error(e)
|
||||
} else if !i.IsDir() {
|
||||
return ErrorDestinationIsNotDir.Error(nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func notDirExistCannotClean(filename string, flag byte, targetLink string) liberr.Error {
|
||||
if strings.EqualFold(runtime.GOOS, "windows") {
|
||||
if flag&tar.TypeLink == tar.TypeLink {
|
||||
return nil
|
||||
} else if flag&tar.TypeSymlink == tar.TypeSymlink {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if _, e := os.Stat(filename); e != nil && os.IsNotExist(e) {
|
||||
return nil
|
||||
} else if e != nil {
|
||||
return ErrorDestinationStat.Error(e)
|
||||
} else if flag&tar.TypeLink == tar.TypeLink || flag&tar.TypeSymlink == tar.TypeSymlink {
|
||||
if hasFSLink(filename) && compareLinkTarget(filename, targetLink) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if e := os.Remove(filename); e != nil {
|
||||
err := ErrorDestinationRemove.Error(e)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func hasFSLink(path string) bool {
|
||||
link, _ := filepath.EvalSymlinks(path)
|
||||
|
||||
if link != "" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func createLink(link, target string, sym bool) liberr.Error {
|
||||
if strings.EqualFold(runtime.GOOS, "windows") {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, e := os.Stat(link); e != nil && !os.IsNotExist(e) {
|
||||
return ErrorDestinationStat.Error(e)
|
||||
} else if e == nil {
|
||||
return nil
|
||||
} else if compareLinkTarget(link, target) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if sym {
|
||||
err := os.Symlink(libarc.CleanPath(target), libarc.CleanPath(link))
|
||||
if err != nil {
|
||||
return ErrorLinkCreate.Error(err)
|
||||
}
|
||||
} else {
|
||||
err := os.Link(libarc.CleanPath(target), libarc.CleanPath(link))
|
||||
if err != nil {
|
||||
return ErrorLinkCreate.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func compareLinkTarget(link, target string) bool {
|
||||
var l string
|
||||
|
||||
l, _ = filepath.EvalSymlinks(link)
|
||||
|
||||
if l == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
return strings.EqualFold(libarc.CleanPath(l), libarc.CleanPath(target))
|
||||
}
|
@@ -1,171 +0,0 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2021 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
package tar
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
func Create(archive io.WriteSeeker, stripPath string, comment string, content ...string) (bool, liberr.Error) {
|
||||
|
||||
if _, err := archive.Seek(0, io.SeekStart); err != nil {
|
||||
return false, ErrorFileSeek.Error(err)
|
||||
}
|
||||
|
||||
if ok, err := createTar(archive, stripPath, content...); err != nil || !ok {
|
||||
return ok, err
|
||||
}
|
||||
|
||||
if _, err := archive.Seek(0, io.SeekStart); err != nil {
|
||||
return false, ErrorFileSeek.Error(err)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func CreateGzip(archive io.WriteSeeker, stripPath string, comment string, content ...string) (bool, liberr.Error) {
|
||||
|
||||
if _, err := archive.Seek(0, io.SeekStart); err != nil {
|
||||
return false, ErrorFileSeek.Error(err)
|
||||
}
|
||||
|
||||
z := gzip.NewWriter(archive)
|
||||
|
||||
if ok, err := createTar(z, stripPath, content...); err != nil || !ok {
|
||||
return ok, err
|
||||
}
|
||||
|
||||
if err := z.Close(); err != nil {
|
||||
return false, ErrorGzipCreate.Error(err)
|
||||
}
|
||||
|
||||
if _, err := archive.Seek(0, io.SeekStart); err != nil {
|
||||
return false, ErrorFileSeek.Error(err)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func createTar(w io.Writer, stripPath string, content ...string) (bool, liberr.Error) {
|
||||
var (
|
||||
t *tar.Writer
|
||||
n int64
|
||||
|
||||
err error
|
||||
lEr = ErrorTarCreateAddFile.Error(nil)
|
||||
)
|
||||
|
||||
stripPath = strings.TrimLeft(stripPath, "/")
|
||||
t = tar.NewWriter(w)
|
||||
|
||||
for i := 0; i < len(content); i++ {
|
||||
if content[i] == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
err = filepath.Walk(content[i], func(file string, inf os.FileInfo, err error) error {
|
||||
var (
|
||||
e error
|
||||
h *tar.Header
|
||||
f *os.File
|
||||
)
|
||||
|
||||
// generate tar header
|
||||
h, e = tar.FileInfoHeader(inf, file)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
// must provide real name
|
||||
// (see https://golang.org/src/archive/tar/common.go?#L626)
|
||||
h.Name = filepath.ToSlash(file)
|
||||
|
||||
if stripPath != "" {
|
||||
h.Name = filepath.Clean(strings.Replace(strings.TrimLeft(h.Name, "/"), stripPath, "", 1))
|
||||
}
|
||||
h.Name = strings.TrimLeft(h.Name, "/")
|
||||
|
||||
if h.Name == "" || h.Name == "." {
|
||||
return nil
|
||||
}
|
||||
|
||||
// write header
|
||||
if e = t.WriteHeader(h); e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
// if not a dir, write file content
|
||||
if !inf.IsDir() {
|
||||
//nolint #gosec
|
||||
/* #nosec */
|
||||
f, e = os.Open(file)
|
||||
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
if _, e = io.Copy(t, f); e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
n++
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
lEr.Add(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if n < 1 {
|
||||
if lEr.HasParent() {
|
||||
return false, lEr
|
||||
}
|
||||
|
||||
//nolint #goerr113
|
||||
return false, ErrorTarCreate.Error(fmt.Errorf("no file to add in archive"))
|
||||
} else if !lEr.HasParent() {
|
||||
lEr = nil
|
||||
}
|
||||
|
||||
if err = t.Close(); err != nil {
|
||||
return false, ErrorTarCreate.Error(err)
|
||||
}
|
||||
|
||||
return true, lEr
|
||||
}
|
44
archive/writecloser.go
Normal file
44
archive/writecloser.go
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package archive
|
||||
|
||||
import "io"
|
||||
|
||||
func NopWriteCloser(w io.Writer) io.WriteCloser {
|
||||
return &wrp{w: w}
|
||||
}
|
||||
|
||||
type wrp struct {
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func (o *wrp) Write(p []byte) (n int, err error) {
|
||||
return o.w.Write(p)
|
||||
}
|
||||
|
||||
func (o *wrp) Close() error {
|
||||
return nil
|
||||
}
|
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package zip
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
arcmod "github.com/nabbar/golib/archive/archive"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
const pkgName = "golib/archive/zip"
|
||||
|
||||
const (
|
||||
ErrorParamEmpty liberr.CodeError = iota + arcmod.MinPkgArchiveZip
|
||||
ErrorFileOpen
|
||||
ErrorFileClose
|
||||
ErrorFileSeek
|
||||
ErrorFileStat
|
||||
ErrorIOCopy
|
||||
ErrorZipOpen
|
||||
ErrorZipCreate
|
||||
ErrorZipComment
|
||||
ErrorZipAddFile
|
||||
ErrorZipFileOpen
|
||||
ErrorZipFileClose
|
||||
ErrorDirCreate
|
||||
ErrorDestinationStat
|
||||
ErrorDestinationIsDir
|
||||
ErrorDestinationIsNotDir
|
||||
ErrorDestinationRemove
|
||||
)
|
||||
|
||||
func init() {
|
||||
if liberr.ExistInMapMessage(ErrorParamEmpty) {
|
||||
panic(fmt.Errorf("error code collision %s", pkgName))
|
||||
}
|
||||
liberr.RegisterIdFctMessage(ErrorParamEmpty, getMessage)
|
||||
}
|
||||
|
||||
func getMessage(code liberr.CodeError) (message string) {
|
||||
switch code {
|
||||
case liberr.UnknownError:
|
||||
return liberr.NullMessage
|
||||
case ErrorParamEmpty:
|
||||
return "given parameters is empty"
|
||||
case ErrorFileOpen:
|
||||
return "cannot open zipped file"
|
||||
case ErrorFileClose:
|
||||
return "closing file occurs error"
|
||||
case ErrorFileStat:
|
||||
return "getting file stat occurs error"
|
||||
case ErrorFileSeek:
|
||||
return "cannot seek into file"
|
||||
case ErrorIOCopy:
|
||||
return "io copy occurs error"
|
||||
case ErrorZipOpen:
|
||||
return "cannot open zip file"
|
||||
case ErrorZipCreate:
|
||||
return "cannot create zip file"
|
||||
case ErrorZipComment:
|
||||
return "cannot set comment to zip file"
|
||||
case ErrorZipAddFile:
|
||||
return "cannot add file to zip file"
|
||||
case ErrorZipFileOpen:
|
||||
return "cannot open file into zip file"
|
||||
case ErrorZipFileClose:
|
||||
return "cannot flose file into zip file"
|
||||
case ErrorDirCreate:
|
||||
return "make directory occurs error"
|
||||
case ErrorDestinationStat:
|
||||
return "cannot stat destination"
|
||||
case ErrorDestinationIsDir:
|
||||
return "cannot create destination not directory over an existing directory"
|
||||
case ErrorDestinationIsNotDir:
|
||||
return "cannot create destination directory over an existing non directory"
|
||||
case ErrorDestinationRemove:
|
||||
return "cannot remove destination "
|
||||
}
|
||||
|
||||
return liberr.NullMessage
|
||||
}
|
@@ -1,216 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package zip
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
arcmod "github.com/nabbar/golib/archive/archive"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
libfpg "github.com/nabbar/golib/file/progress"
|
||||
)
|
||||
|
||||
func GetFile(src, dst libfpg.Progress, filenameContain, filenameRegex string) liberr.Error {
|
||||
var (
|
||||
arc *zip.Reader
|
||||
inf os.FileInfo
|
||||
err error
|
||||
)
|
||||
|
||||
if _, err = src.Seek(0, io.SeekStart); err != nil {
|
||||
return ErrorFileSeek.Error(err)
|
||||
} else if _, err = dst.Seek(0, io.SeekStart); err != nil {
|
||||
return ErrorFileSeek.Error(err)
|
||||
} else if inf, err = src.Stat(); err != nil {
|
||||
return ErrorFileStat.Error(err)
|
||||
} else if arc, err = zip.NewReader(src, inf.Size()); err != nil {
|
||||
return ErrorZipOpen.Error(err)
|
||||
}
|
||||
|
||||
for _, f := range arc.File {
|
||||
if f.Mode()&os.ModeType == os.ModeType {
|
||||
continue
|
||||
}
|
||||
|
||||
z := arcmod.NewFileFullPath(f.Name)
|
||||
|
||||
if z.MatchingFullPath(filenameContain) || z.RegexFullPath(filenameRegex) {
|
||||
if f == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var (
|
||||
r io.ReadCloser
|
||||
e error
|
||||
)
|
||||
|
||||
if r, e = f.Open(); e != nil {
|
||||
//logger.ErrorLevel.LogErrorCtx(logger.DebugLevel, "open zipped file reader", err)
|
||||
return ErrorZipFileOpen.Error(e)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = r.Close()
|
||||
}()
|
||||
|
||||
//nolint #nosec
|
||||
/* #nosec */
|
||||
if _, e = dst.ReadFrom(r); e != nil {
|
||||
//logger.ErrorLevel.LogErrorCtx(logger.DebugLevel, "copy buffer from archive reader", err)
|
||||
return ErrorIOCopy.Error(e)
|
||||
}
|
||||
|
||||
if _, e = dst.Seek(0, io.SeekStart); e != nil {
|
||||
//logger.ErrorLevel.LogErrorCtx(logger.DebugLevel, "seeking temp file", err)
|
||||
return ErrorFileSeek.Error(e)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAll(src libfpg.Progress, outputFolder string, defaultDirPerm os.FileMode) liberr.Error {
|
||||
var (
|
||||
r *zip.Reader
|
||||
i os.FileInfo
|
||||
e error
|
||||
)
|
||||
|
||||
if _, e = src.Seek(0, io.SeekStart); e != nil {
|
||||
return ErrorFileSeek.Error(e)
|
||||
} else if i, e = src.Stat(); e != nil {
|
||||
return ErrorFileStat.Error(e)
|
||||
} else if r, e = zip.NewReader(src, i.Size()); e != nil {
|
||||
return ErrorZipOpen.Error(e)
|
||||
}
|
||||
|
||||
for _, f := range r.File {
|
||||
if f == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
dst := filepath.Join(outputFolder, arcmod.CleanPath(strings.Replace(f.Name, ".."+string(filepath.Separator), "..", -1)))
|
||||
|
||||
// #nosec
|
||||
if err := writeContent(f, dst, defaultDirPerm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeContent(f *zip.File, out string, defaultDirPerm os.FileMode) (err liberr.Error) {
|
||||
var (
|
||||
dst libfpg.Progress
|
||||
inf = f.FileInfo()
|
||||
|
||||
r io.ReadCloser
|
||||
e error
|
||||
)
|
||||
|
||||
if err = dirIsExistOrCreate(filepath.Dir(out), defaultDirPerm); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if dst != nil {
|
||||
if e = dst.Close(); e != nil {
|
||||
err = ErrorFileClose.Error(e)
|
||||
err.Add(err)
|
||||
}
|
||||
}
|
||||
if r != nil {
|
||||
if e = r.Close(); e != nil {
|
||||
err = ErrorZipFileClose.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if inf.IsDir() {
|
||||
err = dirIsExistOrCreate(out, inf.Mode())
|
||||
return
|
||||
} else if inf.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||
return nil
|
||||
} else if err = notDirExistCannotClean(out); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if dst, e = libfpg.New(out, os.O_RDWR|os.O_CREATE|os.O_TRUNC, inf.Mode()); e != nil {
|
||||
return ErrorFileOpen.Error(e)
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
if r, e = f.Open(); e != nil {
|
||||
return ErrorZipFileOpen.Error(e)
|
||||
}
|
||||
|
||||
// #nosec
|
||||
_, e = io.Copy(dst, r)
|
||||
|
||||
if e != nil {
|
||||
return ErrorIOCopy.Error(e)
|
||||
} else if e = dst.Close(); e != nil {
|
||||
return ErrorFileClose.Error(e)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func dirIsExistOrCreate(dirname string, dirPerm os.FileMode) liberr.Error {
|
||||
if i, e := os.Stat(filepath.Dir(dirname)); e != nil && os.IsNotExist(e) {
|
||||
if e = os.MkdirAll(filepath.Dir(dirname), dirPerm); e != nil {
|
||||
return ErrorDirCreate.Error(e)
|
||||
}
|
||||
} else if e != nil {
|
||||
return ErrorDestinationStat.Error(e)
|
||||
} else if !i.IsDir() {
|
||||
return ErrorDestinationIsNotDir.Error(nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func notDirExistCannotClean(filename string) liberr.Error {
|
||||
if i, e := os.Stat(filename); e != nil && !os.IsNotExist(e) {
|
||||
return ErrorDestinationStat.Error(e)
|
||||
} else if e == nil && i.IsDir() {
|
||||
return ErrorDestinationIsDir.Error(nil)
|
||||
} else if e == nil {
|
||||
if e = os.Remove(filename); e != nil {
|
||||
return ErrorDestinationRemove.Error(e)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package zip
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"compress/flate"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
func Create(archive io.WriteSeeker, stripPath string, comment string, content ...string) (bool, liberr.Error) {
|
||||
|
||||
if _, err := archive.Seek(0, io.SeekStart); err != nil {
|
||||
return false, ErrorFileSeek.Error(err)
|
||||
}
|
||||
|
||||
var (
|
||||
z = zip.NewWriter(archive)
|
||||
)
|
||||
|
||||
if z == nil {
|
||||
return false, ErrorZipOpen.Error(nil)
|
||||
} else {
|
||||
z.RegisterCompressor(zip.Deflate, func(out io.Writer) (io.WriteCloser, error) {
|
||||
return flate.NewWriter(out, flate.BestCompression)
|
||||
})
|
||||
}
|
||||
|
||||
if comment != "" {
|
||||
if e := z.SetComment(comment); e != nil {
|
||||
return false, ErrorZipComment.Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
if ok, err := addFileToZip(z, stripPath, content...); err != nil || !ok {
|
||||
return ok, err
|
||||
}
|
||||
|
||||
if _, err := archive.Seek(0, io.SeekStart); err != nil {
|
||||
return false, ErrorFileSeek.Error(err)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func addFileToZip(z *zip.Writer, stripPath string, content ...string) (bool, liberr.Error) {
|
||||
var (
|
||||
n int64
|
||||
err error
|
||||
w io.Writer
|
||||
lEr = ErrorZipAddFile.Error(nil)
|
||||
)
|
||||
|
||||
stripPath = strings.TrimLeft(stripPath, "/")
|
||||
|
||||
for i := 0; i < len(content); i++ {
|
||||
if content[i] == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
err = filepath.Walk(content[i], func(file string, inf os.FileInfo, err error) error {
|
||||
var (
|
||||
e error
|
||||
h *zip.FileHeader
|
||||
f *os.File
|
||||
)
|
||||
|
||||
// generate tar header
|
||||
h, e = zip.FileInfoHeader(inf)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
// must provide real name
|
||||
// (see https://golang.org/src/archive/tar/common.go?#L626)
|
||||
h.Name = filepath.ToSlash(file)
|
||||
|
||||
if stripPath != "" {
|
||||
h.Name = filepath.Clean(strings.Replace(strings.TrimLeft(h.Name, "/"), stripPath, "", 1))
|
||||
}
|
||||
|
||||
h.Name = strings.TrimLeft(h.Name, "/")
|
||||
|
||||
if h.Name == "" || h.Name == "." {
|
||||
return nil
|
||||
}
|
||||
|
||||
// write header
|
||||
if w, e = z.CreateHeader(h); e != nil {
|
||||
return e
|
||||
} else if !inf.IsDir() {
|
||||
// if not a dir, write file content
|
||||
|
||||
//nolint #gosec
|
||||
/* #nosec */
|
||||
f, e = os.Open(file)
|
||||
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
if _, e = io.Copy(w, f); e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
n++
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
lEr.Add(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if n < 1 {
|
||||
if lEr.HasParent() {
|
||||
return false, lEr
|
||||
}
|
||||
|
||||
return false, ErrorZipCreate.Error(fmt.Errorf("no file to add in archive"))
|
||||
} else if !lEr.HasParent() {
|
||||
lEr = nil
|
||||
}
|
||||
|
||||
if err = z.Close(); err != nil {
|
||||
return false, ErrorZipCreate.Error(err)
|
||||
}
|
||||
|
||||
return true, lEr
|
||||
}
|
6
go.mod
6
go.mod
@@ -14,6 +14,7 @@ require (
|
||||
github.com/aws/smithy-go v1.20.1
|
||||
github.com/bits-and-blooms/bitset v1.13.0
|
||||
github.com/c-bata/go-prompt v0.2.6
|
||||
github.com/dsnet/compress v0.0.1
|
||||
github.com/fatih/color v1.16.0
|
||||
github.com/fsnotify/fsnotify v1.7.0
|
||||
github.com/fxamacker/cbor/v2 v2.6.0
|
||||
@@ -35,9 +36,10 @@ require (
|
||||
github.com/nats-io/nats-server/v2 v2.10.12
|
||||
github.com/nats-io/nats.go v1.34.0
|
||||
github.com/nutsdb/nutsdb v0.14.3
|
||||
github.com/onsi/ginkgo/v2 v2.17.0
|
||||
github.com/onsi/ginkgo/v2 v2.17.1
|
||||
github.com/onsi/gomega v1.32.0
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/pierrec/lz4/v4 v4.1.21
|
||||
github.com/prometheus/client_golang v1.19.0
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
@@ -45,6 +47,7 @@ require (
|
||||
github.com/spf13/jwalterweatherman v1.1.0
|
||||
github.com/spf13/viper v1.18.2
|
||||
github.com/ugorji/go/codec v1.2.12
|
||||
github.com/ulikunitz/xz v0.5.11
|
||||
github.com/vbauerster/mpb/v8 v8.7.2
|
||||
github.com/xanzy/go-gitlab v0.101.0
|
||||
github.com/xhit/go-simple-mail v2.2.2+incompatible
|
||||
@@ -174,7 +177,6 @@ require (
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/paulmach/orb v0.11.1 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/term v1.2.0-beta.2 // indirect
|
||||
github.com/prometheus/client_model v0.5.0 // indirect
|
||||
|
@@ -33,11 +33,13 @@ package nutsdb
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
libfpg "github.com/nabbar/golib/file/progress"
|
||||
arcarc "github.com/nabbar/golib/archive/archive"
|
||||
arctps "github.com/nabbar/golib/archive/archive/types"
|
||||
|
||||
"github.com/nabbar/golib/archive"
|
||||
libarc "github.com/nabbar/golib/archive"
|
||||
arccmp "github.com/nabbar/golib/archive/compress"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
"github.com/nutsdb/nutsdb"
|
||||
)
|
||||
@@ -86,30 +88,27 @@ func (s *snap) Prepare(opt Options, db *nutsdb.DB) liberr.Error {
|
||||
func (s *snap) Save(opt Options, writer io.Writer) liberr.Error {
|
||||
var (
|
||||
e error
|
||||
|
||||
tmp libfpg.Progress
|
||||
err liberr.Error
|
||||
g io.WriteCloser
|
||||
t arctps.Writer
|
||||
f = func(str string) string {
|
||||
return strings.TrimPrefix(str, s.path)
|
||||
}
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if tmp != nil {
|
||||
_ = tmp.CloseDelete()
|
||||
if t != nil {
|
||||
_ = t.Close()
|
||||
}
|
||||
if g != nil {
|
||||
_ = g.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
if tmp, e = libfpg.Unique(opt.GetTempDir(), opt.NewTempFilePattern("tar")); e != nil {
|
||||
return ErrorFileTemp.Error(e)
|
||||
}
|
||||
|
||||
if _, err = archive.CreateArchive(archive.TypeTarGzip, tmp, s.path, s.path); err != nil {
|
||||
return ErrorFolderArchive.Error(err)
|
||||
}
|
||||
|
||||
if _, e = tmp.Seek(0, io.SeekStart); e != nil {
|
||||
if g, e = arccmp.Gzip.Writer(libarc.NopWriteCloser(writer)); e != nil {
|
||||
return ErrorDatabaseSnapshot.Error(e)
|
||||
}
|
||||
|
||||
if _, e = tmp.WriteTo(writer); e != nil {
|
||||
} else if t, e = arcarc.Tar.Writer(g); e != nil {
|
||||
return ErrorDatabaseSnapshot.Error(e)
|
||||
} else if e = t.FromPath(s.path, "", f); e != nil {
|
||||
return ErrorDatabaseSnapshot.Error(e)
|
||||
}
|
||||
|
||||
@@ -118,38 +117,21 @@ func (s *snap) Save(opt Options, writer io.Writer) liberr.Error {
|
||||
|
||||
func (s *snap) Load(opt Options, reader io.Reader) liberr.Error {
|
||||
var (
|
||||
a string
|
||||
o string
|
||||
e error
|
||||
|
||||
tmp libfpg.Progress
|
||||
err liberr.Error
|
||||
d string
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if tmp != nil {
|
||||
_ = tmp.CloseDelete()
|
||||
}
|
||||
}()
|
||||
|
||||
if tmp, e = libfpg.Unique(opt.GetTempDir(), opt.NewTempFilePattern("tar.gz")); e != nil {
|
||||
return ErrorFileTemp.Error(e)
|
||||
}
|
||||
|
||||
if _, e = tmp.ReadFrom(reader); e != nil {
|
||||
if d, e = opt.NewTempFolder(); e != nil {
|
||||
return ErrorDatabaseSnapshot.Error(e)
|
||||
} else if e = libarc.ExtractAll(io.NopCloser(reader), "unknown", d); e != nil {
|
||||
return ErrorDatabaseSnapshot.Error(e)
|
||||
} else {
|
||||
s.path = d
|
||||
}
|
||||
|
||||
if o, err = opt.NewTempFolder(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = archive.ExtractAll(tmp, filepath.Base(a), o, opt.Permission()); err != nil {
|
||||
return ErrorFolderExtract.Error(err)
|
||||
}
|
||||
|
||||
s.path = o
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@@ -1,99 +0,0 @@
|
||||
//+build examples
|
||||
//go:build examples
|
||||
// +build examples
|
||||
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/nabbar/golib/archive"
|
||||
"github.com/nabbar/golib/errors"
|
||||
"github.com/nabbar/golib/ioutils"
|
||||
"github.com/nabbar/golib/logger"
|
||||
)
|
||||
|
||||
// git archive --format=tar --output=git.tar HEAD && gzip git.tar
|
||||
const fileName = "./git.tar.gz"
|
||||
|
||||
func main() {
|
||||
var (
|
||||
src ioutils.FileProgress
|
||||
tmp ioutils.FileProgress
|
||||
out string
|
||||
err error
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if src != nil {
|
||||
_ = src.Close()
|
||||
}
|
||||
if tmp != nil {
|
||||
_ = tmp.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
logger.SetLevel(logger.DebugLevel)
|
||||
logger.EnableColor()
|
||||
logger.FileTrace(true)
|
||||
errors.SetModeReturnError(errors.ErrorReturnCodeErrorTraceFull)
|
||||
|
||||
if src, err = ioutils.NewFileProgressPathOpen(fileName); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if tmp, err = ioutils.NewFileProgressTemp(); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
out = tmp.FilePath()
|
||||
_ = tmp.Close()
|
||||
}
|
||||
|
||||
if err = archive.ExtractAll(src, path.Base(src.FilePath()), out, 0775); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if list, e := ioutil.ReadDir(out); e != nil {
|
||||
panic(e)
|
||||
} else {
|
||||
for _, f := range list {
|
||||
var (
|
||||
isDir bool
|
||||
isLink bool
|
||||
isFile bool
|
||||
)
|
||||
isDir = f.IsDir()
|
||||
isLink = f.Mode()&os.ModeSymlink == os.ModeSymlink
|
||||
isFile = !isLink && !isDir
|
||||
println(fmt.Sprintf("Item '%s' is Dir '%v', is Link '%v', is File '%v'", f.Name(), isDir, isLink, isFile))
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,100 +0,0 @@
|
||||
//go:build examples
|
||||
// +build examples
|
||||
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/nabbar/golib/errors"
|
||||
|
||||
"github.com/nabbar/golib/archive"
|
||||
"github.com/nabbar/golib/ioutils"
|
||||
)
|
||||
|
||||
// git archive --format=tar --output=git.tar HEAD
|
||||
// const fileName = "./git.tar"
|
||||
const fileName = "./vendor.zip"
|
||||
|
||||
// const contain = "version/license_mit.go"
|
||||
const contain = "vendor/github.com/gin-gonic/gin/internal/json/json.go"
|
||||
|
||||
// const regex = ""
|
||||
const regex = "vendor\\.tar(\\.(?:gz|bz))?"
|
||||
|
||||
func main() {
|
||||
var (
|
||||
src ioutils.FileProgress
|
||||
tmp ioutils.FileProgress
|
||||
rio ioutils.FileProgress
|
||||
err errors.Error
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if src != nil {
|
||||
_ = src.Close()
|
||||
}
|
||||
if tmp != nil {
|
||||
_ = tmp.Close()
|
||||
}
|
||||
if rio != nil {
|
||||
_ = rio.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
if src, err = ioutils.NewFileProgressPathOpen(fileName); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if tmp, err = ioutils.NewFileProgressTemp(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if rio, err = ioutils.NewFileProgressTemp(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if _, e := tmp.ReadFrom(src); e != nil {
|
||||
panic(e)
|
||||
}
|
||||
|
||||
if err = archive.ExtractFile(tmp, rio, contain, regex); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if _, e := rio.Seek(0, io.SeekStart); e != nil {
|
||||
panic(e)
|
||||
}
|
||||
|
||||
if b, e := ioutil.ReadAll(rio); e != nil {
|
||||
panic(e)
|
||||
} else {
|
||||
println(string(b))
|
||||
}
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
[ ! -e vendor.tar.gz ] || rm -v vendor.tar.gz
|
||||
[ ! -e vendor.tar.bz2 ] || rm -v vendor.tar.bz2
|
||||
[ ! -e vendor.zip ] || rm -v vendor.zip
|
||||
[ ! -e ph-000.tar ] || rm -v ph-00*.tar
|
||||
[ ! -e test-archive ] || rm -v test-archive
|
||||
|
||||
tar cf ph-000.tar vendor/ && \
|
||||
cp -v ph-000.tar ph-001.tar && \
|
||||
cp -v ph-000.tar ph-002.tar && \
|
||||
cp -v ph-000.tar ph-003.tar && \
|
||||
cp -v ph-000.tar ph-004.tar && \
|
||||
cp -v ph-000.tar ph-005.tar && \
|
||||
cp -v ph-000.tar ph-006.tar && \
|
||||
cp -v ph-000.tar ph-007.tar && \
|
||||
cp -v ph-000.tar ph-008.tar && \
|
||||
cp -v ph-000.tar ph-009.tar && \
|
||||
tar czf vendor.tar.gz vendor/ && \
|
||||
tar cjf vendor.tar.bz2 ph-00*.tar vendor.tar.gz && \
|
||||
zip vendor.zip ph-00*.tar vendor.tar.bz2 && \
|
||||
rm -vf ph-00*.tar vendor.tar.* && \
|
||||
ls -ahl vendor.zip && \
|
||||
go build -a -v -o test-archive ./test/test-archive/ && \
|
||||
echo -e "\n\n\t>>Try to print contents of file github.com/gin-gonic/gin/internal/json/json.go" && \
|
||||
./test-archive
|
||||
echo -e "\n\n\t>>from archive zip >> bz2 >> tar >> gz >> tar :" && \
|
||||
ls -ahl vendor.zip && \
|
||||
echo -e "\n\n"
|
||||
|
||||
[ ! -e vendor.tar.gz ] || rm -v vendor.tar.gz
|
||||
[ ! -e vendor.tar.bz2 ] || rm -v vendor.tar.bz2
|
||||
[ ! -e vendor.zip ] || rm -v vendor.zip
|
||||
[ ! -e ph-000.tar ] || rm -v ph-00*.tar
|
||||
[ ! -e test-archive ] || rm -v test-archive
|
Reference in New Issue
Block a user