youtubebeat/vendor/github.com/elastic/beats/dev-tools/mage/copy.go

148 lines
3.9 KiB
Go

// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package mage
import (
"io"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"github.com/pkg/errors"
)
// Copy copies a file or a directory (recursively) and preserves the permissions.
func Copy(src, dest string) error {
copy := &CopyTask{Source: src, Dest: dest}
return copy.Execute()
}
// CopyTask copies a file or directory (recursively) and preserves the permissions.
type CopyTask struct {
Source string // Source directory or file.
Dest string // Destination directory or file.
Mode os.FileMode // Mode to use for copied files. Defaults to preserve permissions.
DirMode os.FileMode // Mode to use for copied dirs. Defaults to preserve permissions.
Exclude []string // Exclude paths that match these regular expressions.
excludes []*regexp.Regexp // Compiled exclude regexes.
}
// Execute executes the copy and returns an error of there is a failure.
func (t *CopyTask) Execute() error {
if err := t.init(); err != nil {
return errors.Wrap(err, "copy failed")
}
info, err := os.Stat(t.Source)
if err != nil {
return errors.Wrapf(err, "copy failed: cannot stat source file %v", t.Source)
}
return errors.Wrap(t.recursiveCopy(t.Source, t.Dest, info), "copy failed")
}
func (t *CopyTask) init() error {
for _, excl := range t.Exclude {
re, err := regexp.Compile(excl)
if err != nil {
return errors.Wrapf(err, "bad exclude pattern %v", excl)
}
t.excludes = append(t.excludes, re)
}
return nil
}
func (t *CopyTask) isExcluded(src string) bool {
for _, excl := range t.excludes {
if match := excl.MatchString(filepath.ToSlash(src)); match {
return true
}
}
return false
}
func (t *CopyTask) recursiveCopy(src, dest string, info os.FileInfo) error {
if info.IsDir() {
return t.dirCopy(src, dest, info)
}
return t.fileCopy(src, dest, info)
}
func (t *CopyTask) fileCopy(src, dest string, info os.FileInfo) error {
if t.isExcluded(src) {
return nil
}
srcFile, err := os.Open(src)
if err != nil {
return err
}
defer srcFile.Close()
if !info.Mode().IsRegular() {
return errors.Errorf("failed to copy source file because it is not a " +
"regular file")
}
mode := t.Mode
if mode == 0 {
mode = info.Mode()
}
destFile, err := os.OpenFile(createDir(dest),
os.O_CREATE|os.O_TRUNC|os.O_WRONLY, mode&os.ModePerm)
if err != nil {
return err
}
defer destFile.Close()
if _, err = io.Copy(destFile, srcFile); err != nil {
return err
}
return destFile.Close()
}
func (t *CopyTask) dirCopy(src, dest string, info os.FileInfo) error {
if t.isExcluded(src) {
return nil
}
mode := t.DirMode
if mode == 0 {
mode = info.Mode()
}
if err := os.MkdirAll(dest, mode&os.ModePerm); err != nil {
return errors.Wrap(err, "failed creating dirs")
}
contents, err := ioutil.ReadDir(src)
if err != nil {
return errors.Wrapf(err, "failed to read dir %v", src)
}
for _, info := range contents {
srcFile := filepath.Join(src, info.Name())
destFile := filepath.Join(dest, info.Name())
if err = t.recursiveCopy(srcFile, destFile, info); err != nil {
return errors.Wrapf(err, "failed to copy %v to %v", srcFile, destFile)
}
}
return nil
}