github.com/webx-top/com@v1.2.12/dir.go (about)

     1  // Copyright 2013 com authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"): you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    11  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    12  // License for the specific language governing permissions and limitations
    13  // under the License.
    14  
    15  package com
    16  
    17  import (
    18  	"errors"
    19  	"os"
    20  	"path/filepath"
    21  	"strings"
    22  )
    23  
    24  // IsDir returns true if given path is a directory,
    25  // or returns false when it's a file or does not exist.
    26  func IsDir(dir string) bool {
    27  	f, e := os.Stat(dir)
    28  	if e != nil {
    29  		return false
    30  	}
    31  	return f.IsDir()
    32  }
    33  
    34  func statDir(dirPath, recPath string, includeDir, isDirOnly bool) ([]string, error) {
    35  	dir, err := os.Open(dirPath)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	defer dir.Close()
    40  
    41  	fis, err := dir.Readdir(0)
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  
    46  	var statList []string
    47  	for _, fi := range fis {
    48  		if strings.Contains(fi.Name(), ".DS_Store") {
    49  			continue
    50  		}
    51  
    52  		relPath := filepath.Join(recPath, fi.Name())
    53  		curPath := filepath.Join(dirPath, fi.Name())
    54  		if fi.IsDir() {
    55  			if includeDir {
    56  				statList = append(statList, relPath+"/")
    57  			}
    58  			s, err := statDir(curPath, relPath, includeDir, isDirOnly)
    59  			if err != nil {
    60  				return nil, err
    61  			}
    62  			statList = append(statList, s...)
    63  		} else if !isDirOnly {
    64  			statList = append(statList, relPath)
    65  		}
    66  	}
    67  	return statList, nil
    68  }
    69  
    70  // StatDir gathers information of given directory by depth-first.
    71  // It returns slice of file list and includes subdirectories if enabled;
    72  // it returns error and nil slice when error occurs in underlying functions,
    73  // or given path is not a directory or does not exist.
    74  //
    75  // Slice does not include given path itself.
    76  // If subdirectories is enabled, they will have suffix '/'.
    77  func StatDir(rootPath string, includeDir ...bool) ([]string, error) {
    78  	if !IsDir(rootPath) {
    79  		return nil, errors.New("not a directory or does not exist: " + rootPath)
    80  	}
    81  
    82  	isIncludeDir := false
    83  	if len(includeDir) >= 1 {
    84  		isIncludeDir = includeDir[0]
    85  	}
    86  	return statDir(rootPath, "", isIncludeDir, false)
    87  }
    88  
    89  // GetAllSubDirs returns all subdirectories of given root path.
    90  // Slice does not include given path itself.
    91  func GetAllSubDirs(rootPath string) ([]string, error) {
    92  	if !IsDir(rootPath) {
    93  		return nil, errors.New("not a directory or does not exist: " + rootPath)
    94  	}
    95  	return statDir(rootPath, "", true, true)
    96  }
    97  
    98  // CopyDir copy files recursively from source to target directory.
    99  //
   100  // The filter accepts a function that process the path info.
   101  // and should return true for need to filter.
   102  //
   103  // It returns error when error occurs in underlying functions.
   104  func CopyDir(srcPath, destPath string, filters ...func(filePath string) bool) error {
   105  	// Check if target directory exists.
   106  	if !IsExist(destPath) {
   107  		err := os.MkdirAll(destPath, os.ModePerm)
   108  		if err != nil {
   109  			return err
   110  		}
   111  	}
   112  
   113  	// Gather directory info.
   114  	infos, err := StatDir(srcPath, true)
   115  	if err != nil {
   116  		return err
   117  	}
   118  
   119  	var filter func(filePath string) bool
   120  	if len(filters) > 0 {
   121  		filter = filters[0]
   122  	}
   123  
   124  	for _, info := range infos {
   125  		if filter != nil && filter(info) {
   126  			continue
   127  		}
   128  
   129  		curPath := filepath.Join(destPath, info)
   130  		if strings.HasSuffix(info, "/") {
   131  			err = os.MkdirAll(curPath, os.ModePerm)
   132  		} else {
   133  			err = Copy(filepath.Join(srcPath, info), curPath)
   134  		}
   135  		if err != nil {
   136  			return err
   137  		}
   138  	}
   139  	return nil
   140  }
   141  
   142  func FindNotExistsDirs(dir string) ([]string, error) {
   143  	var notExistsDirs []string
   144  	oldParent := dir
   145  	parent := filepath.Dir(dir)
   146  	for oldParent != parent {
   147  		_, err := os.Stat(parent)
   148  		if err == nil {
   149  			break
   150  		}
   151  		if !os.IsNotExist(err) {
   152  			return notExistsDirs, err
   153  		}
   154  		notExistsDirs = append(notExistsDirs, parent)
   155  		oldParent = parent
   156  		parent = filepath.Dir(parent)
   157  	}
   158  	return notExistsDirs, nil
   159  }
   160  
   161  func MkdirAll(dir string, mode os.FileMode) error {
   162  	if fi, err := os.Stat(dir); err == nil {
   163  		if fi.IsDir() {
   164  			if fi.Mode().Perm() != mode.Perm() {
   165  				return os.Chmod(dir, mode)
   166  			}
   167  			return nil
   168  		}
   169  	}
   170  	needChmodDirs, err := FindNotExistsDirs(dir)
   171  	if err != nil {
   172  		return err
   173  	}
   174  	//Dump(needChmodDirs)
   175  
   176  	err = os.MkdirAll(dir, mode)
   177  	if err != nil {
   178  		return err
   179  	}
   180  	err = os.Chmod(dir, mode)
   181  	if err != nil {
   182  		return err
   183  	}
   184  	for _, dir := range needChmodDirs {
   185  		err = os.Chmod(dir, mode)
   186  		if err != nil {
   187  			return err
   188  		}
   189  	}
   190  	return err
   191  }