user8557463
user8557463

Reputation:

Create archive exclude base dir

I’ve directory with lots of files that I need to zip, I found this https://github.com/mholt/archiver OS What I need is to exclude base dir while archiving and I didnt find this on the docs

i.e zip only the files inside the folder without the parent folder

The code I use is like following

err := archiver.Zip.Make(“mydir.zip", []string{path2Dir})

How Can I do it ?

If there is other good solution in go please let me know

Upvotes: 2

Views: 527

Answers (1)

Anuruddha
Anuruddha

Reputation: 3245

archiver library always append the baseDir to the header names. Refer to line no: 111 of zip.go. I don't see an option here to use this library without modification to suite your needs.

Internally this library is using archive/zip. I've modified the ziping code to suit your requirement. Hope the code is self explanatory.

package main

import (
    "archive/zip"
    "fmt"
    "os"

    "path/filepath"
    "strings"
    "path"
    "io"
)

var compressedFormats = map[string]struct{}{
    ".7z":   {},
    ".avi":  {},
    ".bz2":  {},
    ".cab":  {},
    ".gif":  {},
    ".gz":   {},
    ".jar":  {},
    ".jpeg": {},
    ".jpg":  {},
    ".lz":   {},
    ".lzma": {},
    ".mov":  {},
    ".mp3":  {},
    ".mp4":  {},
    ".mpeg": {},
    ".mpg":  {},
    ".png":  {},
    ".rar":  {},
    ".tbz2": {},
    ".tgz":  {},
    ".txz":  {},
    ".xz":   {},
    ".zip":  {},
    ".zipx": {},
}

func Zip(source, ou string) error {
    out, err := os.Create(ou)
    if err != nil {
        return fmt.Errorf("error creating %s: %v", ou, err)
    }
    defer out.Close()
    // Create a new zip archive.
    w := zip.NewWriter(out)
    sourceInfo, err := os.Stat(source)
    if err != nil {
        return fmt.Errorf("%s: stat: %v", source, err)
    }
    defer w.Close()
    var baseDir string
    if sourceInfo.IsDir() {
        baseDir = filepath.Base(source)
    }

    return filepath.Walk(source, func(fpath string, info os.FileInfo, err error) error {
        if baseDir == fpath {
            //skip the base diectory
            return nil
        }
        if err != nil {
            return fmt.Errorf("walking to %s: %v", fpath, err)
        }

        header, err := zip.FileInfoHeader(info)
        if err != nil {
            return fmt.Errorf("%s: getting header: %v", fpath, err)
        }

        if baseDir != "" {
            name, err := filepath.Rel(source, fpath)
            if err != nil {
                return err
            }
            header.Name = filepath.ToSlash(name)
        }

        if info.IsDir() {
            header.Name += "/"
            header.Method = zip.Store
        } else {
            ext := strings.ToLower(path.Ext(header.Name))
            if _, ok := compressedFormats[ext]; ok {
                header.Method = zip.Store
            } else {
                header.Method = zip.Deflate
            }
        }

        writer, err := w.CreateHeader(header)
        if err != nil {
            return fmt.Errorf("%s: making header: %v", fpath, err)
        }

        if info.IsDir() {
            return nil
        }

        if header.Mode().IsRegular() {
            file, err := os.Open(fpath)
            if err != nil {
                return fmt.Errorf("%s: opening: %v", fpath, err)
            }
            defer file.Close()

            _, err = io.CopyN(writer, file, info.Size())
            if err != nil && err != io.EOF {
                return fmt.Errorf("%s: copying contents: %v", fpath, err)
            }
        }
        return nil
    })
}

func main() {
    err := Zip("caddy", "result.zip")
    if err != nil {
        fmt.Println(err.Error())
    }
}

Upvotes: 2

Related Questions