Home | History | Annotate | Download | only in pathtools
      1 // Copyright 2016 Google Inc. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain 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,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package pathtools
     16 
     17 import (
     18 	"bytes"
     19 	"fmt"
     20 	"io"
     21 	"io/ioutil"
     22 	"os"
     23 	"path/filepath"
     24 )
     25 
     26 // Based on Andrew Gerrand's "10 things you (probably) dont' know about Go"
     27 
     28 var OsFs FileSystem = osFs{}
     29 
     30 func MockFs(files map[string][]byte) FileSystem {
     31 	fs := &mockFs{
     32 		files: make(map[string][]byte, len(files)),
     33 		dirs:  make(map[string]bool),
     34 		all:   []string(nil),
     35 	}
     36 
     37 	for f, b := range files {
     38 		fs.files[filepath.Clean(f)] = b
     39 		dir := filepath.Dir(f)
     40 		for dir != "." && dir != "/" {
     41 			fs.dirs[dir] = true
     42 			dir = filepath.Dir(dir)
     43 		}
     44 		fs.dirs[dir] = true
     45 	}
     46 
     47 	for f := range fs.files {
     48 		fs.all = append(fs.all, f)
     49 	}
     50 
     51 	for d := range fs.dirs {
     52 		fs.all = append(fs.all, d)
     53 	}
     54 
     55 	return fs
     56 }
     57 
     58 type FileSystem interface {
     59 	Open(name string) (io.ReadCloser, error)
     60 	Exists(name string) (bool, bool, error)
     61 	Glob(pattern string, excludes []string) (matches, dirs []string, err error)
     62 	glob(pattern string) (matches []string, err error)
     63 	IsDir(name string) (bool, error)
     64 }
     65 
     66 // osFs implements FileSystem using the local disk.
     67 type osFs struct{}
     68 
     69 func (osFs) Open(name string) (io.ReadCloser, error) { return os.Open(name) }
     70 func (osFs) Exists(name string) (bool, bool, error) {
     71 	stat, err := os.Stat(name)
     72 	if err == nil {
     73 		return true, stat.IsDir(), nil
     74 	} else if os.IsNotExist(err) {
     75 		return false, false, nil
     76 	} else {
     77 		return false, false, err
     78 	}
     79 }
     80 
     81 func (osFs) IsDir(name string) (bool, error) {
     82 	info, err := os.Stat(name)
     83 	if err != nil {
     84 		return false, fmt.Errorf("unexpected error after glob: %s", err)
     85 	}
     86 	return info.IsDir(), nil
     87 }
     88 
     89 func (fs osFs) Glob(pattern string, excludes []string) (matches, dirs []string, err error) {
     90 	return startGlob(fs, pattern, excludes)
     91 }
     92 
     93 func (osFs) glob(pattern string) ([]string, error) {
     94 	return filepath.Glob(pattern)
     95 }
     96 
     97 type mockFs struct {
     98 	files map[string][]byte
     99 	dirs  map[string]bool
    100 	all   []string
    101 }
    102 
    103 func (m *mockFs) Open(name string) (io.ReadCloser, error) {
    104 	if f, ok := m.files[name]; ok {
    105 		return struct {
    106 			io.Closer
    107 			*bytes.Reader
    108 		}{
    109 			ioutil.NopCloser(nil),
    110 			bytes.NewReader(f),
    111 		}, nil
    112 	}
    113 
    114 	return nil, &os.PathError{
    115 		Op:   "open",
    116 		Path: name,
    117 		Err:  os.ErrNotExist,
    118 	}
    119 }
    120 
    121 func (m *mockFs) Exists(name string) (bool, bool, error) {
    122 	name = filepath.Clean(name)
    123 	if _, ok := m.files[name]; ok {
    124 		return ok, false, nil
    125 	}
    126 	if _, ok := m.dirs[name]; ok {
    127 		return ok, true, nil
    128 	}
    129 	return false, false, nil
    130 }
    131 
    132 func (m *mockFs) IsDir(name string) (bool, error) {
    133 	return m.dirs[filepath.Clean(name)], nil
    134 }
    135 
    136 func (m *mockFs) Glob(pattern string, excludes []string) (matches, dirs []string, err error) {
    137 	return startGlob(m, pattern, excludes)
    138 }
    139 
    140 func (m *mockFs) glob(pattern string) ([]string, error) {
    141 	var matches []string
    142 	for _, f := range m.all {
    143 		match, err := filepath.Match(pattern, f)
    144 		if err != nil {
    145 			return nil, err
    146 		}
    147 		if match {
    148 			matches = append(matches, f)
    149 		}
    150 	}
    151 	return matches, nil
    152 }
    153