aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/spf13
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/spf13')
-rw-r--r--vendor/github.com/spf13/afero/.travis.yml21
-rw-r--r--vendor/github.com/spf13/afero/LICENSE.txt174
-rw-r--r--vendor/github.com/spf13/afero/README.md452
-rw-r--r--vendor/github.com/spf13/afero/afero.go108
-rw-r--r--vendor/github.com/spf13/afero/appveyor.yml15
-rw-r--r--vendor/github.com/spf13/afero/basepath.go180
-rw-r--r--vendor/github.com/spf13/afero/cacheOnReadFs.go290
-rw-r--r--vendor/github.com/spf13/afero/const_bsds.go22
-rw-r--r--vendor/github.com/spf13/afero/const_win_unix.go25
-rw-r--r--vendor/github.com/spf13/afero/copyOnWriteFs.go293
-rw-r--r--vendor/github.com/spf13/afero/go.mod3
-rw-r--r--vendor/github.com/spf13/afero/go.sum2
-rw-r--r--vendor/github.com/spf13/afero/httpFs.go110
-rw-r--r--vendor/github.com/spf13/afero/ioutil.go230
-rw-r--r--vendor/github.com/spf13/afero/lstater.go27
-rw-r--r--vendor/github.com/spf13/afero/match.go110
-rw-r--r--vendor/github.com/spf13/afero/mem/dir.go37
-rw-r--r--vendor/github.com/spf13/afero/mem/dirmap.go43
-rw-r--r--vendor/github.com/spf13/afero/mem/file.go317
-rw-r--r--vendor/github.com/spf13/afero/memmap.go365
-rw-r--r--vendor/github.com/spf13/afero/os.go101
-rw-r--r--vendor/github.com/spf13/afero/path.go106
-rw-r--r--vendor/github.com/spf13/afero/readonlyfs.go80
-rw-r--r--vendor/github.com/spf13/afero/regexpfs.go214
-rw-r--r--vendor/github.com/spf13/afero/unionFile.go316
-rw-r--r--vendor/github.com/spf13/afero/util.go330
26 files changed, 3971 insertions, 0 deletions
diff --git a/vendor/github.com/spf13/afero/.travis.yml b/vendor/github.com/spf13/afero/.travis.yml
new file mode 100644
index 0000000..0637db7
--- /dev/null
+++ b/vendor/github.com/spf13/afero/.travis.yml
@@ -0,0 +1,21 @@
1sudo: false
2language: go
3
4go:
5 - 1.9
6 - "1.10"
7 - tip
8
9os:
10 - linux
11 - osx
12
13matrix:
14 allow_failures:
15 - go: tip
16 fast_finish: true
17
18script:
19 - go build
20 - go test -race -v ./...
21
diff --git a/vendor/github.com/spf13/afero/LICENSE.txt b/vendor/github.com/spf13/afero/LICENSE.txt
new file mode 100644
index 0000000..298f0e2
--- /dev/null
+++ b/vendor/github.com/spf13/afero/LICENSE.txt
@@ -0,0 +1,174 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
diff --git a/vendor/github.com/spf13/afero/README.md b/vendor/github.com/spf13/afero/README.md
new file mode 100644
index 0000000..0c9b04b
--- /dev/null
+++ b/vendor/github.com/spf13/afero/README.md
@@ -0,0 +1,452 @@
1![afero logo-sm](https://cloud.githubusercontent.com/assets/173412/11490338/d50e16dc-97a5-11e5-8b12-019a300d0fcb.png)
2
3A FileSystem Abstraction System for Go
4
5[![Build Status](https://travis-ci.org/spf13/afero.svg)](https://travis-ci.org/spf13/afero) [![Build status](https://ci.appveyor.com/api/projects/status/github/spf13/afero?branch=master&svg=true)](https://ci.appveyor.com/project/spf13/afero) [![GoDoc](https://godoc.org/github.com/spf13/afero?status.svg)](https://godoc.org/github.com/spf13/afero) [![Join the chat at https://gitter.im/spf13/afero](https://badges.gitter.im/Dev%20Chat.svg)](https://gitter.im/spf13/afero?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
6
7# Overview
8
9Afero is an filesystem framework providing a simple, uniform and universal API
10interacting with any filesystem, as an abstraction layer providing interfaces,
11types and methods. Afero has an exceptionally clean interface and simple design
12without needless constructors or initialization methods.
13
14Afero is also a library providing a base set of interoperable backend
15filesystems that make it easy to work with afero while retaining all the power
16and benefit of the os and ioutil packages.
17
18Afero provides significant improvements over using the os package alone, most
19notably the ability to create mock and testing filesystems without relying on the disk.
20
21It is suitable for use in a any situation where you would consider using the OS
22package as it provides an additional abstraction that makes it easy to use a
23memory backed file system during testing. It also adds support for the http
24filesystem for full interoperability.
25
26
27## Afero Features
28
29* A single consistent API for accessing a variety of filesystems
30* Interoperation between a variety of file system types
31* A set of interfaces to encourage and enforce interoperability between backends
32* An atomic cross platform memory backed file system
33* Support for compositional (union) file systems by combining multiple file systems acting as one
34* Specialized backends which modify existing filesystems (Read Only, Regexp filtered)
35* A set of utility functions ported from io, ioutil & hugo to be afero aware
36
37
38# Using Afero
39
40Afero is easy to use and easier to adopt.
41
42A few different ways you could use Afero:
43
44* Use the interfaces alone to define you own file system.
45* Wrap for the OS packages.
46* Define different filesystems for different parts of your application.
47* Use Afero for mock filesystems while testing
48
49## Step 1: Install Afero
50
51First use go get to install the latest version of the library.
52
53 $ go get github.com/spf13/afero
54
55Next include Afero in your application.
56```go
57import "github.com/spf13/afero"
58```
59
60## Step 2: Declare a backend
61
62First define a package variable and set it to a pointer to a filesystem.
63```go
64var AppFs = afero.NewMemMapFs()
65
66or
67
68var AppFs = afero.NewOsFs()
69```
70It is important to note that if you repeat the composite literal you
71will be using a completely new and isolated filesystem. In the case of
72OsFs it will still use the same underlying filesystem but will reduce
73the ability to drop in other filesystems as desired.
74
75## Step 3: Use it like you would the OS package
76
77Throughout your application use any function and method like you normally
78would.
79
80So if my application before had:
81```go
82os.Open('/tmp/foo')
83```
84We would replace it with:
85```go
86AppFs.Open('/tmp/foo')
87```
88
89`AppFs` being the variable we defined above.
90
91
92## List of all available functions
93
94File System Methods Available:
95```go
96Chmod(name string, mode os.FileMode) : error
97Chtimes(name string, atime time.Time, mtime time.Time) : error
98Create(name string) : File, error
99Mkdir(name string, perm os.FileMode) : error
100MkdirAll(path string, perm os.FileMode) : error
101Name() : string
102Open(name string) : File, error
103OpenFile(name string, flag int, perm os.FileMode) : File, error
104Remove(name string) : error
105RemoveAll(path string) : error
106Rename(oldname, newname string) : error
107Stat(name string) : os.FileInfo, error
108```
109File Interfaces and Methods Available:
110```go
111io.Closer
112io.Reader
113io.ReaderAt
114io.Seeker
115io.Writer
116io.WriterAt
117
118Name() : string
119Readdir(count int) : []os.FileInfo, error
120Readdirnames(n int) : []string, error
121Stat() : os.FileInfo, error
122Sync() : error
123Truncate(size int64) : error
124WriteString(s string) : ret int, err error
125```
126In some applications it may make sense to define a new package that
127simply exports the file system variable for easy access from anywhere.
128
129## Using Afero's utility functions
130
131Afero provides a set of functions to make it easier to use the underlying file systems.
132These functions have been primarily ported from io & ioutil with some developed for Hugo.
133
134The afero utilities support all afero compatible backends.
135
136The list of utilities includes:
137
138```go
139DirExists(path string) (bool, error)
140Exists(path string) (bool, error)
141FileContainsBytes(filename string, subslice []byte) (bool, error)
142GetTempDir(subPath string) string
143IsDir(path string) (bool, error)
144IsEmpty(path string) (bool, error)
145ReadDir(dirname string) ([]os.FileInfo, error)
146ReadFile(filename string) ([]byte, error)
147SafeWriteReader(path string, r io.Reader) (err error)
148TempDir(dir, prefix string) (name string, err error)
149TempFile(dir, prefix string) (f File, err error)
150Walk(root string, walkFn filepath.WalkFunc) error
151WriteFile(filename string, data []byte, perm os.FileMode) error
152WriteReader(path string, r io.Reader) (err error)
153```
154For a complete list see [Afero's GoDoc](https://godoc.org/github.com/spf13/afero)
155
156They are available under two different approaches to use. You can either call
157them directly where the first parameter of each function will be the file
158system, or you can declare a new `Afero`, a custom type used to bind these
159functions as methods to a given filesystem.
160
161### Calling utilities directly
162
163```go
164fs := new(afero.MemMapFs)
165f, err := afero.TempFile(fs,"", "ioutil-test")
166
167```
168
169### Calling via Afero
170
171```go
172fs := afero.NewMemMapFs()
173afs := &afero.Afero{Fs: fs}
174f, err := afs.TempFile("", "ioutil-test")
175```
176
177## Using Afero for Testing
178
179There is a large benefit to using a mock filesystem for testing. It has a
180completely blank state every time it is initialized and can be easily
181reproducible regardless of OS. You could create files to your heart’s content
182and the file access would be fast while also saving you from all the annoying
183issues with deleting temporary files, Windows file locking, etc. The MemMapFs
184backend is perfect for testing.
185
186* Much faster than performing I/O operations on disk
187* Avoid security issues and permissions
188* Far more control. 'rm -rf /' with confidence
189* Test setup is far more easier to do
190* No test cleanup needed
191
192One way to accomplish this is to define a variable as mentioned above.
193In your application this will be set to afero.NewOsFs() during testing you
194can set it to afero.NewMemMapFs().
195
196It wouldn't be uncommon to have each test initialize a blank slate memory
197backend. To do this I would define my `appFS = afero.NewOsFs()` somewhere
198appropriate in my application code. This approach ensures that Tests are order
199independent, with no test relying on the state left by an earlier test.
200
201Then in my tests I would initialize a new MemMapFs for each test:
202```go
203func TestExist(t *testing.T) {
204 appFS := afero.NewMemMapFs()
205 // create test files and directories
206 appFS.MkdirAll("src/a", 0755)
207 afero.WriteFile(appFS, "src/a/b", []byte("file b"), 0644)
208 afero.WriteFile(appFS, "src/c", []byte("file c"), 0644)
209 name := "src/c"
210 _, err := appFS.Stat(name)
211 if os.IsNotExist(err) {
212 t.Errorf("file \"%s\" does not exist.\n", name)
213 }
214}
215```
216
217# Available Backends
218
219## Operating System Native
220
221### OsFs
222
223The first is simply a wrapper around the native OS calls. This makes it
224very easy to use as all of the calls are the same as the existing OS
225calls. It also makes it trivial to have your code use the OS during
226operation and a mock filesystem during testing or as needed.
227
228```go
229appfs := afero.NewOsFs()
230appfs.MkdirAll("src/a", 0755))
231```
232
233## Memory Backed Storage
234
235### MemMapFs
236
237Afero also provides a fully atomic memory backed filesystem perfect for use in
238mocking and to speed up unnecessary disk io when persistence isn’t
239necessary. It is fully concurrent and will work within go routines
240safely.
241
242```go
243mm := afero.NewMemMapFs()
244mm.MkdirAll("src/a", 0755))
245```
246
247#### InMemoryFile
248
249As part of MemMapFs, Afero also provides an atomic, fully concurrent memory
250backed file implementation. This can be used in other memory backed file
251systems with ease. Plans are to add a radix tree memory stored file
252system using InMemoryFile.
253
254## Network Interfaces
255
256### SftpFs
257
258Afero has experimental support for secure file transfer protocol (sftp). Which can
259be used to perform file operations over a encrypted channel.
260
261## Filtering Backends
262
263### BasePathFs
264
265The BasePathFs restricts all operations to a given path within an Fs.
266The given file name to the operations on this Fs will be prepended with
267the base path before calling the source Fs.
268
269```go
270bp := afero.NewBasePathFs(afero.NewOsFs(), "/base/path")
271```
272
273### ReadOnlyFs
274
275A thin wrapper around the source Fs providing a read only view.
276
277```go
278fs := afero.NewReadOnlyFs(afero.NewOsFs())
279_, err := fs.Create("/file.txt")
280// err = syscall.EPERM
281```
282
283# RegexpFs
284
285A filtered view on file names, any file NOT matching
286the passed regexp will be treated as non-existing.
287Files not matching the regexp provided will not be created.
288Directories are not filtered.
289
290```go
291fs := afero.NewRegexpFs(afero.NewMemMapFs(), regexp.MustCompile(`\.txt$`))
292_, err := fs.Create("/file.html")
293// err = syscall.ENOENT
294```
295
296### HttpFs
297
298Afero provides an http compatible backend which can wrap any of the existing
299backends.
300
301The Http package requires a slightly specific version of Open which
302returns an http.File type.
303
304Afero provides an httpFs file system which satisfies this requirement.
305Any Afero FileSystem can be used as an httpFs.
306
307```go
308httpFs := afero.NewHttpFs(<ExistingFS>)
309fileserver := http.FileServer(httpFs.Dir(<PATH>)))
310http.Handle("/", fileserver)
311```
312
313## Composite Backends
314
315Afero provides the ability have two filesystems (or more) act as a single
316file system.
317
318### CacheOnReadFs
319
320The CacheOnReadFs will lazily make copies of any accessed files from the base
321layer into the overlay. Subsequent reads will be pulled from the overlay
322directly permitting the request is within the cache duration of when it was
323created in the overlay.
324
325If the base filesystem is writeable, any changes to files will be
326done first to the base, then to the overlay layer. Write calls to open file
327handles like `Write()` or `Truncate()` to the overlay first.
328
329To writing files to the overlay only, you can use the overlay Fs directly (not
330via the union Fs).
331
332Cache files in the layer for the given time.Duration, a cache duration of 0
333means "forever" meaning the file will not be re-requested from the base ever.
334
335A read-only base will make the overlay also read-only but still copy files
336from the base to the overlay when they're not present (or outdated) in the
337caching layer.
338
339```go
340base := afero.NewOsFs()
341layer := afero.NewMemMapFs()
342ufs := afero.NewCacheOnReadFs(base, layer, 100 * time.Second)
343```
344
345### CopyOnWriteFs()
346
347The CopyOnWriteFs is a read only base file system with a potentially
348writeable layer on top.
349
350Read operations will first look in the overlay and if not found there, will
351serve the file from the base.
352
353Changes to the file system will only be made in the overlay.
354
355Any attempt to modify a file found only in the base will copy the file to the
356overlay layer before modification (including opening a file with a writable
357handle).
358
359Removing and Renaming files present only in the base layer is not currently
360permitted. If a file is present in the base layer and the overlay, only the
361overlay will be removed/renamed.
362
363```go
364 base := afero.NewOsFs()
365 roBase := afero.NewReadOnlyFs(base)
366 ufs := afero.NewCopyOnWriteFs(roBase, afero.NewMemMapFs())
367
368 fh, _ = ufs.Create("/home/test/file2.txt")
369 fh.WriteString("This is a test")
370 fh.Close()
371```
372
373In this example all write operations will only occur in memory (MemMapFs)
374leaving the base filesystem (OsFs) untouched.
375
376
377## Desired/possible backends
378
379The following is a short list of possible backends we hope someone will
380implement:
381
382* SSH
383* ZIP
384* TAR
385* S3
386
387# About the project
388
389## What's in the name
390
391Afero comes from the latin roots Ad-Facere.
392
393**"Ad"** is a prefix meaning "to".
394
395**"Facere"** is a form of the root "faciō" making "make or do".
396
397The literal meaning of afero is "to make" or "to do" which seems very fitting
398for a library that allows one to make files and directories and do things with them.
399
400The English word that shares the same roots as Afero is "affair". Affair shares
401the same concept but as a noun it means "something that is made or done" or "an
402object of a particular type".
403
404It's also nice that unlike some of my other libraries (hugo, cobra, viper) it
405Googles very well.
406
407## Release Notes
408
409* **0.10.0** 2015.12.10
410 * Full compatibility with Windows
411 * Introduction of afero utilities
412 * Test suite rewritten to work cross platform
413 * Normalize paths for MemMapFs
414 * Adding Sync to the file interface
415 * **Breaking Change** Walk and ReadDir have changed parameter order
416 * Moving types used by MemMapFs to a subpackage
417 * General bugfixes and improvements
418* **0.9.0** 2015.11.05
419 * New Walk function similar to filepath.Walk
420 * MemMapFs.OpenFile handles O_CREATE, O_APPEND, O_TRUNC
421 * MemMapFs.Remove now really deletes the file
422 * InMemoryFile.Readdir and Readdirnames work correctly
423 * InMemoryFile functions lock it for concurrent access
424 * Test suite improvements
425* **0.8.0** 2014.10.28
426 * First public version
427 * Interfaces feel ready for people to build using
428 * Interfaces satisfy all known uses
429 * MemMapFs passes the majority of the OS test suite
430 * OsFs passes the majority of the OS test suite
431
432## Contributing
433
4341. Fork it
4352. Create your feature branch (`git checkout -b my-new-feature`)
4363. Commit your changes (`git commit -am 'Add some feature'`)
4374. Push to the branch (`git push origin my-new-feature`)
4385. Create new Pull Request
439
440## Contributors
441
442Names in no particular order:
443
444* [spf13](https://github.com/spf13)
445* [jaqx0r](https://github.com/jaqx0r)
446* [mbertschler](https://github.com/mbertschler)
447* [xor-gate](https://github.com/xor-gate)
448
449## License
450
451Afero is released under the Apache 2.0 license. See
452[LICENSE.txt](https://github.com/spf13/afero/blob/master/LICENSE.txt)
diff --git a/vendor/github.com/spf13/afero/afero.go b/vendor/github.com/spf13/afero/afero.go
new file mode 100644
index 0000000..f5b5e12
--- /dev/null
+++ b/vendor/github.com/spf13/afero/afero.go
@@ -0,0 +1,108 @@
1// Copyright © 2014 Steve Francia <spf@spf13.com>.
2// Copyright 2013 tsuru authors. All rights reserved.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
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 afero provides types and methods for interacting with the filesystem,
16// as an abstraction layer.
17
18// Afero also provides a few implementations that are mostly interoperable. One that
19// uses the operating system filesystem, one that uses memory to store files
20// (cross platform) and an interface that should be implemented if you want to
21// provide your own filesystem.
22
23package afero
24
25import (
26 "errors"
27 "io"
28 "os"
29 "time"
30)
31
32type Afero struct {
33 Fs
34}
35
36// File represents a file in the filesystem.
37type File interface {
38 io.Closer
39 io.Reader
40 io.ReaderAt
41 io.Seeker
42 io.Writer
43 io.WriterAt
44
45 Name() string
46 Readdir(count int) ([]os.FileInfo, error)
47 Readdirnames(n int) ([]string, error)
48 Stat() (os.FileInfo, error)
49 Sync() error
50 Truncate(size int64) error
51 WriteString(s string) (ret int, err error)
52}
53
54// Fs is the filesystem interface.
55//
56// Any simulated or real filesystem should implement this interface.
57type Fs interface {
58 // Create creates a file in the filesystem, returning the file and an
59 // error, if any happens.
60 Create(name string) (File, error)
61
62 // Mkdir creates a directory in the filesystem, return an error if any
63 // happens.
64 Mkdir(name string, perm os.FileMode) error
65
66 // MkdirAll creates a directory path and all parents that does not exist
67 // yet.
68 MkdirAll(path string, perm os.FileMode) error
69
70 // Open opens a file, returning it or an error, if any happens.
71 Open(name string) (File, error)
72
73 // OpenFile opens a file using the given flags and the given mode.
74 OpenFile(name string, flag int, perm os.FileMode) (File, error)
75
76 // Remove removes a file identified by name, returning an error, if any
77 // happens.
78 Remove(name string) error
79
80 // RemoveAll removes a directory path and any children it contains. It
81 // does not fail if the path does not exist (return nil).
82 RemoveAll(path string) error
83
84 // Rename renames a file.
85 Rename(oldname, newname string) error
86
87 // Stat returns a FileInfo describing the named file, or an error, if any
88 // happens.
89 Stat(name string) (os.FileInfo, error)
90
91 // The name of this FileSystem
92 Name() string
93
94 //Chmod changes the mode of the named file to mode.
95 Chmod(name string, mode os.FileMode) error
96
97 //Chtimes changes the access and modification times of the named file
98 Chtimes(name string, atime time.Time, mtime time.Time) error
99}
100
101var (
102 ErrFileClosed = errors.New("File is closed")
103 ErrOutOfRange = errors.New("Out of range")
104 ErrTooLarge = errors.New("Too large")
105 ErrFileNotFound = os.ErrNotExist
106 ErrFileExists = os.ErrExist
107 ErrDestinationExists = os.ErrExist
108)
diff --git a/vendor/github.com/spf13/afero/appveyor.yml b/vendor/github.com/spf13/afero/appveyor.yml
new file mode 100644
index 0000000..a633ad5
--- /dev/null
+++ b/vendor/github.com/spf13/afero/appveyor.yml
@@ -0,0 +1,15 @@
1version: '{build}'
2clone_folder: C:\gopath\src\github.com\spf13\afero
3environment:
4 GOPATH: C:\gopath
5build_script:
6- cmd: >-
7 go version
8
9 go env
10
11 go get -v github.com/spf13/afero/...
12
13 go build github.com/spf13/afero
14test_script:
15- cmd: go test -race -v github.com/spf13/afero/...
diff --git a/vendor/github.com/spf13/afero/basepath.go b/vendor/github.com/spf13/afero/basepath.go
new file mode 100644
index 0000000..616ff8f
--- /dev/null
+++ b/vendor/github.com/spf13/afero/basepath.go
@@ -0,0 +1,180 @@
1package afero
2
3import (
4 "os"
5 "path/filepath"
6 "runtime"
7 "strings"
8 "time"
9)
10
11var _ Lstater = (*BasePathFs)(nil)
12
13// The BasePathFs restricts all operations to a given path within an Fs.
14// The given file name to the operations on this Fs will be prepended with
15// the base path before calling the base Fs.
16// Any file name (after filepath.Clean()) outside this base path will be
17// treated as non existing file.
18//
19// Note that it does not clean the error messages on return, so you may
20// reveal the real path on errors.
21type BasePathFs struct {
22 source Fs
23 path string
24}
25
26type BasePathFile struct {
27 File
28 path string
29}
30
31func (f *BasePathFile) Name() string {
32 sourcename := f.File.Name()
33 return strings.TrimPrefix(sourcename, filepath.Clean(f.path))
34}
35
36func NewBasePathFs(source Fs, path string) Fs {
37 return &BasePathFs{source: source, path: path}
38}
39
40// on a file outside the base path it returns the given file name and an error,
41// else the given file with the base path prepended
42func (b *BasePathFs) RealPath(name string) (path string, err error) {
43 if err := validateBasePathName(name); err != nil {
44 return name, err
45 }
46
47 bpath := filepath.Clean(b.path)
48 path = filepath.Clean(filepath.Join(bpath, name))
49 if !strings.HasPrefix(path, bpath) {
50 return name, os.ErrNotExist
51 }
52
53 return path, nil
54}
55
56func validateBasePathName(name string) error {
57 if runtime.GOOS != "windows" {
58 // Not much to do here;
59 // the virtual file paths all look absolute on *nix.
60 return nil
61 }
62
63 // On Windows a common mistake would be to provide an absolute OS path
64 // We could strip out the base part, but that would not be very portable.
65 if filepath.IsAbs(name) {
66 return os.ErrNotExist
67 }
68
69 return nil
70}
71
72func (b *BasePathFs) Chtimes(name string, atime, mtime time.Time) (err error) {
73 if name, err = b.RealPath(name); err != nil {
74 return &os.PathError{Op: "chtimes", Path: name, Err: err}
75 }
76 return b.source.Chtimes(name, atime, mtime)
77}
78
79func (b *BasePathFs) Chmod(name string, mode os.FileMode) (err error) {
80 if name, err = b.RealPath(name); err != nil {
81 return &os.PathError{Op: "chmod", Path: name, Err: err}
82 }
83 return b.source.Chmod(name, mode)
84}
85
86func (b *BasePathFs) Name() string {
87 return "BasePathFs"
88}
89
90func (b *BasePathFs) Stat(name string) (fi os.FileInfo, err error) {
91 if name, err = b.RealPath(name); err != nil {
92 return nil, &os.PathError{Op: "stat", Path: name, Err: err}
93 }
94 return b.source.Stat(name)
95}
96
97func (b *BasePathFs) Rename(oldname, newname string) (err error) {
98 if oldname, err = b.RealPath(oldname); err != nil {
99 return &os.PathError{Op: "rename", Path: oldname, Err: err}
100 }
101 if newname, err = b.RealPath(newname); err != nil {
102 return &os.PathError{Op: "rename", Path: newname, Err: err}
103 }
104 return b.source.Rename(oldname, newname)
105}
106
107func (b *BasePathFs) RemoveAll(name string) (err error) {
108 if name, err = b.RealPath(name); err != nil {
109 return &os.PathError{Op: "remove_all", Path: name, Err: err}
110 }
111 return b.source.RemoveAll(name)
112}
113
114func (b *BasePathFs) Remove(name string) (err error) {
115 if name, err = b.RealPath(name); err != nil {
116 return &os.PathError{Op: "remove", Path: name, Err: err}
117 }
118 return b.source.Remove(name)
119}
120
121func (b *BasePathFs) OpenFile(name string, flag int, mode os.FileMode) (f File, err error) {
122 if name, err = b.RealPath(name); err != nil {
123 return nil, &os.PathError{Op: "openfile", Path: name, Err: err}
124 }
125 sourcef, err := b.source.OpenFile(name, flag, mode)
126 if err != nil {
127 return nil, err
128 }
129 return &BasePathFile{sourcef, b.path}, nil
130}
131
132func (b *BasePathFs) Open(name string) (f File, err error) {
133 if name, err = b.RealPath(name); err != nil {
134 return nil, &os.PathError{Op: "open", Path: name, Err: err}
135 }
136 sourcef, err := b.source.Open(name)
137 if err != nil {
138 return nil, err
139 }
140 return &BasePathFile{File: sourcef, path: b.path}, nil
141}
142
143func (b *BasePathFs) Mkdir(name string, mode os.FileMode) (err error) {
144 if name, err = b.RealPath(name); err != nil {
145 return &os.PathError{Op: "mkdir", Path: name, Err: err}
146 }
147 return b.source.Mkdir(name, mode)
148}
149
150func (b *BasePathFs) MkdirAll(name string, mode os.FileMode) (err error) {
151 if name, err = b.RealPath(name); err != nil {
152 return &os.PathError{Op: "mkdir", Path: name, Err: err}
153 }
154 return b.source.MkdirAll(name, mode)
155}
156
157func (b *BasePathFs) Create(name string) (f File, err error) {
158 if name, err = b.RealPath(name); err != nil {
159 return nil, &os.PathError{Op: "create", Path: name, Err: err}
160 }
161 sourcef, err := b.source.Create(name)
162 if err != nil {
163 return nil, err
164 }
165 return &BasePathFile{File: sourcef, path: b.path}, nil
166}
167
168func (b *BasePathFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
169 name, err := b.RealPath(name)
170 if err != nil {
171 return nil, false, &os.PathError{Op: "lstat", Path: name, Err: err}
172 }
173 if lstater, ok := b.source.(Lstater); ok {
174 return lstater.LstatIfPossible(name)
175 }
176 fi, err := b.source.Stat(name)
177 return fi, false, err
178}
179
180// vim: ts=4 sw=4 noexpandtab nolist syn=go
diff --git a/vendor/github.com/spf13/afero/cacheOnReadFs.go b/vendor/github.com/spf13/afero/cacheOnReadFs.go
new file mode 100644
index 0000000..29a26c6
--- /dev/null
+++ b/vendor/github.com/spf13/afero/cacheOnReadFs.go
@@ -0,0 +1,290 @@
1package afero
2
3import (
4 "os"
5 "syscall"
6 "time"
7)
8
9// If the cache duration is 0, cache time will be unlimited, i.e. once
10// a file is in the layer, the base will never be read again for this file.
11//
12// For cache times greater than 0, the modification time of a file is
13// checked. Note that a lot of file system implementations only allow a
14// resolution of a second for timestamps... or as the godoc for os.Chtimes()
15// states: "The underlying filesystem may truncate or round the values to a
16// less precise time unit."
17//
18// This caching union will forward all write calls also to the base file
19// system first. To prevent writing to the base Fs, wrap it in a read-only
20// filter - Note: this will also make the overlay read-only, for writing files
21// in the overlay, use the overlay Fs directly, not via the union Fs.
22type CacheOnReadFs struct {
23 base Fs
24 layer Fs
25 cacheTime time.Duration
26}
27
28func NewCacheOnReadFs(base Fs, layer Fs, cacheTime time.Duration) Fs {
29 return &CacheOnReadFs{base: base, layer: layer, cacheTime: cacheTime}
30}
31
32type cacheState int
33
34const (
35 // not present in the overlay, unknown if it exists in the base:
36 cacheMiss cacheState = iota
37 // present in the overlay and in base, base file is newer:
38 cacheStale
39 // present in the overlay - with cache time == 0 it may exist in the base,
40 // with cacheTime > 0 it exists in the base and is same age or newer in the
41 // overlay
42 cacheHit
43 // happens if someone writes directly to the overlay without
44 // going through this union
45 cacheLocal
46)
47
48func (u *CacheOnReadFs) cacheStatus(name string) (state cacheState, fi os.FileInfo, err error) {
49 var lfi, bfi os.FileInfo
50 lfi, err = u.layer.Stat(name)
51 if err == nil {
52 if u.cacheTime == 0 {
53 return cacheHit, lfi, nil
54 }
55 if lfi.ModTime().Add(u.cacheTime).Before(time.Now()) {
56 bfi, err = u.base.Stat(name)
57 if err != nil {
58 return cacheLocal, lfi, nil
59 }
60 if bfi.ModTime().After(lfi.ModTime()) {
61 return cacheStale, bfi, nil
62 }
63 }
64 return cacheHit, lfi, nil
65 }
66
67 if err == syscall.ENOENT || os.IsNotExist(err) {
68 return cacheMiss, nil, nil
69 }
70
71 return cacheMiss, nil, err
72}
73
74func (u *CacheOnReadFs) copyToLayer(name string) error {
75 return copyToLayer(u.base, u.layer, name)
76}
77
78func (u *CacheOnReadFs) Chtimes(name string, atime, mtime time.Time) error {
79 st, _, err := u.cacheStatus(name)
80 if err != nil {
81 return err
82 }
83 switch st {
84 case cacheLocal:
85 case cacheHit:
86 err = u.base.Chtimes(name, atime, mtime)
87 case cacheStale, cacheMiss:
88 if err := u.copyToLayer(name); err != nil {
89 return err
90 }
91 err = u.base.Chtimes(name, atime, mtime)
92 }
93 if err != nil {
94 return err
95 }
96 return u.layer.Chtimes(name, atime, mtime)
97}
98
99func (u *CacheOnReadFs) Chmod(name string, mode os.FileMode) error {
100 st, _, err := u.cacheStatus(name)
101 if err != nil {
102 return err
103 }
104 switch st {
105 case cacheLocal:
106 case cacheHit:
107 err = u.base.Chmod(name, mode)
108 case cacheStale, cacheMiss:
109 if err := u.copyToLayer(name); err != nil {
110 return err
111 }
112 err = u.base.Chmod(name, mode)
113 }
114 if err != nil {
115 return err
116 }
117 return u.layer.Chmod(name, mode)
118}
119
120func (u *CacheOnReadFs) Stat(name string) (os.FileInfo, error) {
121 st, fi, err := u.cacheStatus(name)
122 if err != nil {
123 return nil, err
124 }
125 switch st {
126 case cacheMiss:
127 return u.base.Stat(name)
128 default: // cacheStale has base, cacheHit and cacheLocal the layer os.FileInfo
129 return fi, nil
130 }
131}
132
133func (u *CacheOnReadFs) Rename(oldname, newname string) error {
134 st, _, err := u.cacheStatus(oldname)
135 if err != nil {
136 return err
137 }
138 switch st {
139 case cacheLocal:
140 case cacheHit:
141 err = u.base.Rename(oldname, newname)
142 case cacheStale, cacheMiss:
143 if err := u.copyToLayer(oldname); err != nil {
144 return err
145 }
146 err = u.base.Rename(oldname, newname)
147 }
148 if err != nil {
149 return err
150 }
151 return u.layer.Rename(oldname, newname)
152}
153
154func (u *CacheOnReadFs) Remove(name string) error {
155 st, _, err := u.cacheStatus(name)
156 if err != nil {
157 return err
158 }
159 switch st {
160 case cacheLocal:
161 case cacheHit, cacheStale, cacheMiss:
162 err = u.base.Remove(name)
163 }
164 if err != nil {
165 return err
166 }
167 return u.layer.Remove(name)
168}
169
170func (u *CacheOnReadFs) RemoveAll(name string) error {
171 st, _, err := u.cacheStatus(name)
172 if err != nil {
173 return err
174 }
175 switch st {
176 case cacheLocal:
177 case cacheHit, cacheStale, cacheMiss:
178 err = u.base.RemoveAll(name)
179 }
180 if err != nil {
181 return err
182 }
183 return u.layer.RemoveAll(name)
184}
185
186func (u *CacheOnReadFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
187 st, _, err := u.cacheStatus(name)
188 if err != nil {
189 return nil, err
190 }
191 switch st {
192 case cacheLocal, cacheHit:
193 default:
194 if err := u.copyToLayer(name); err != nil {
195 return nil, err
196 }
197 }
198 if flag&(os.O_WRONLY|syscall.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 {
199 bfi, err := u.base.OpenFile(name, flag, perm)
200 if err != nil {
201 return nil, err
202 }
203 lfi, err := u.layer.OpenFile(name, flag, perm)
204 if err != nil {
205 bfi.Close() // oops, what if O_TRUNC was set and file opening in the layer failed...?
206 return nil, err
207 }
208 return &UnionFile{Base: bfi, Layer: lfi}, nil
209 }
210 return u.layer.OpenFile(name, flag, perm)
211}
212
213func (u *CacheOnReadFs) Open(name string) (File, error) {
214 st, fi, err := u.cacheStatus(name)
215 if err != nil {
216 return nil, err
217 }
218
219 switch st {
220 case cacheLocal:
221 return u.layer.Open(name)
222
223 case cacheMiss:
224 bfi, err := u.base.Stat(name)
225 if err != nil {
226 return nil, err
227 }
228 if bfi.IsDir() {
229 return u.base.Open(name)
230 }
231 if err := u.copyToLayer(name); err != nil {
232 return nil, err
233 }
234 return u.layer.Open(name)
235
236 case cacheStale:
237 if !fi.IsDir() {
238 if err := u.copyToLayer(name); err != nil {
239 return nil, err
240 }
241 return u.layer.Open(name)
242 }
243 case cacheHit:
244 if !fi.IsDir() {
245 return u.layer.Open(name)
246 }
247 }
248 // the dirs from cacheHit, cacheStale fall down here:
249 bfile, _ := u.base.Open(name)
250 lfile, err := u.layer.Open(name)
251 if err != nil && bfile == nil {
252 return nil, err
253 }
254 return &UnionFile{Base: bfile, Layer: lfile}, nil
255}
256
257func (u *CacheOnReadFs) Mkdir(name string, perm os.FileMode) error {
258 err := u.base.Mkdir(name, perm)
259 if err != nil {
260 return err
261 }
262 return u.layer.MkdirAll(name, perm) // yes, MkdirAll... we cannot assume it exists in the cache
263}
264
265func (u *CacheOnReadFs) Name() string {
266 return "CacheOnReadFs"
267}
268
269func (u *CacheOnReadFs) MkdirAll(name string, perm os.FileMode) error {
270 err := u.base.MkdirAll(name, perm)
271 if err != nil {
272 return err
273 }
274 return u.layer.MkdirAll(name, perm)
275}
276
277func (u *CacheOnReadFs) Create(name string) (File, error) {
278 bfh, err := u.base.Create(name)
279 if err != nil {
280 return nil, err
281 }
282 lfh, err := u.layer.Create(name)
283 if err != nil {
284 // oops, see comment about OS_TRUNC above, should we remove? then we have to
285 // remember if the file did not exist before
286 bfh.Close()
287 return nil, err
288 }
289 return &UnionFile{Base: bfh, Layer: lfh}, nil
290}
diff --git a/vendor/github.com/spf13/afero/const_bsds.go b/vendor/github.com/spf13/afero/const_bsds.go
new file mode 100644
index 0000000..5728243
--- /dev/null
+++ b/vendor/github.com/spf13/afero/const_bsds.go
@@ -0,0 +1,22 @@
1// Copyright © 2016 Steve Francia <spf@spf13.com>.
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// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14// +build darwin openbsd freebsd netbsd dragonfly
15
16package afero
17
18import (
19 "syscall"
20)
21
22const BADFD = syscall.EBADF
diff --git a/vendor/github.com/spf13/afero/const_win_unix.go b/vendor/github.com/spf13/afero/const_win_unix.go
new file mode 100644
index 0000000..968fc27
--- /dev/null
+++ b/vendor/github.com/spf13/afero/const_win_unix.go
@@ -0,0 +1,25 @@
1// Copyright © 2016 Steve Francia <spf@spf13.com>.
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// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13// +build !darwin
14// +build !openbsd
15// +build !freebsd
16// +build !dragonfly
17// +build !netbsd
18
19package afero
20
21import (
22 "syscall"
23)
24
25const BADFD = syscall.EBADFD
diff --git a/vendor/github.com/spf13/afero/copyOnWriteFs.go b/vendor/github.com/spf13/afero/copyOnWriteFs.go
new file mode 100644
index 0000000..e8108a8
--- /dev/null
+++ b/vendor/github.com/spf13/afero/copyOnWriteFs.go
@@ -0,0 +1,293 @@
1package afero
2
3import (
4 "fmt"
5 "os"
6 "path/filepath"
7 "syscall"
8 "time"
9)
10
11var _ Lstater = (*CopyOnWriteFs)(nil)
12
13// The CopyOnWriteFs is a union filesystem: a read only base file system with
14// a possibly writeable layer on top. Changes to the file system will only
15// be made in the overlay: Changing an existing file in the base layer which
16// is not present in the overlay will copy the file to the overlay ("changing"
17// includes also calls to e.g. Chtimes() and Chmod()).
18//
19// Reading directories is currently only supported via Open(), not OpenFile().
20type CopyOnWriteFs struct {
21 base Fs
22 layer Fs
23}
24
25func NewCopyOnWriteFs(base Fs, layer Fs) Fs {
26 return &CopyOnWriteFs{base: base, layer: layer}
27}
28
29// Returns true if the file is not in the overlay
30func (u *CopyOnWriteFs) isBaseFile(name string) (bool, error) {
31 if _, err := u.layer.Stat(name); err == nil {
32 return false, nil
33 }
34 _, err := u.base.Stat(name)
35 if err != nil {
36 if oerr, ok := err.(*os.PathError); ok {
37 if oerr.Err == os.ErrNotExist || oerr.Err == syscall.ENOENT || oerr.Err == syscall.ENOTDIR {
38 return false, nil
39 }
40 }
41 if err == syscall.ENOENT {
42 return false, nil
43 }
44 }
45 return true, err
46}
47
48func (u *CopyOnWriteFs) copyToLayer(name string) error {
49 return copyToLayer(u.base, u.layer, name)
50}
51
52func (u *CopyOnWriteFs) Chtimes(name string, atime, mtime time.Time) error {
53 b, err := u.isBaseFile(name)
54 if err != nil {
55 return err
56 }
57 if b {
58 if err := u.copyToLayer(name); err != nil {
59 return err
60 }
61 }
62 return u.layer.Chtimes(name, atime, mtime)
63}
64
65func (u *CopyOnWriteFs) Chmod(name string, mode os.FileMode) error {
66 b, err := u.isBaseFile(name)
67 if err != nil {
68 return err
69 }
70 if b {
71 if err := u.copyToLayer(name); err != nil {
72 return err
73 }
74 }
75 return u.layer.Chmod(name, mode)
76}
77
78func (u *CopyOnWriteFs) Stat(name string) (os.FileInfo, error) {
79 fi, err := u.layer.Stat(name)
80 if err != nil {
81 isNotExist := u.isNotExist(err)
82 if isNotExist {
83 return u.base.Stat(name)
84 }
85 return nil, err
86 }
87 return fi, nil
88}
89
90func (u *CopyOnWriteFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
91 llayer, ok1 := u.layer.(Lstater)
92 lbase, ok2 := u.base.(Lstater)
93
94 if ok1 {
95 fi, b, err := llayer.LstatIfPossible(name)
96 if err == nil {
97 return fi, b, nil
98 }
99
100 if !u.isNotExist(err) {
101 return nil, b, err
102 }
103 }
104
105 if ok2 {
106 fi, b, err := lbase.LstatIfPossible(name)
107 if err == nil {
108 return fi, b, nil
109 }
110 if !u.isNotExist(err) {
111 return nil, b, err
112 }
113 }
114
115 fi, err := u.Stat(name)
116
117 return fi, false, err
118}
119
120func (u *CopyOnWriteFs) isNotExist(err error) bool {
121 if e, ok := err.(*os.PathError); ok {
122 err = e.Err
123 }
124 if err == os.ErrNotExist || err == syscall.ENOENT || err == syscall.ENOTDIR {
125 return true
126 }
127 return false
128}
129
130// Renaming files present only in the base layer is not permitted
131func (u *CopyOnWriteFs) Rename(oldname, newname string) error {
132 b, err := u.isBaseFile(oldname)
133 if err != nil {
134 return err
135 }
136 if b {
137 return syscall.EPERM
138 }
139 return u.layer.Rename(oldname, newname)
140}
141
142// Removing files present only in the base layer is not permitted. If
143// a file is present in the base layer and the overlay, only the overlay
144// will be removed.
145func (u *CopyOnWriteFs) Remove(name string) error {
146 err := u.layer.Remove(name)
147 switch err {
148 case syscall.ENOENT:
149 _, err = u.base.Stat(name)
150 if err == nil {
151 return syscall.EPERM
152 }
153 return syscall.ENOENT
154 default:
155 return err
156 }
157}
158
159func (u *CopyOnWriteFs) RemoveAll(name string) error {
160 err := u.layer.RemoveAll(name)
161 switch err {
162 case syscall.ENOENT:
163 _, err = u.base.Stat(name)
164 if err == nil {
165 return syscall.EPERM
166 }
167 return syscall.ENOENT
168 default:
169 return err
170 }
171}
172
173func (u *CopyOnWriteFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
174 b, err := u.isBaseFile(name)
175 if err != nil {
176 return nil, err
177 }
178
179 if flag&(os.O_WRONLY|os.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 {
180 if b {
181 if err = u.copyToLayer(name); err != nil {
182 return nil, err
183 }
184 return u.layer.OpenFile(name, flag, perm)
185 }
186
187 dir := filepath.Dir(name)
188 isaDir, err := IsDir(u.base, dir)
189 if err != nil && !os.IsNotExist(err) {
190 return nil, err
191 }
192 if isaDir {
193 if err = u.layer.MkdirAll(dir, 0777); err != nil {
194 return nil, err
195 }
196 return u.layer.OpenFile(name, flag, perm)
197 }
198
199 isaDir, err = IsDir(u.layer, dir)
200 if err != nil {
201 return nil, err
202 }
203 if isaDir {
204 return u.layer.OpenFile(name, flag, perm)
205 }
206
207 return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOTDIR} // ...or os.ErrNotExist?
208 }
209 if b {
210 return u.base.OpenFile(name, flag, perm)
211 }
212 return u.layer.OpenFile(name, flag, perm)
213}
214
215// This function handles the 9 different possibilities caused
216// by the union which are the intersection of the following...
217// layer: doesn't exist, exists as a file, and exists as a directory
218// base: doesn't exist, exists as a file, and exists as a directory
219func (u *CopyOnWriteFs) Open(name string) (File, error) {
220 // Since the overlay overrides the base we check that first
221 b, err := u.isBaseFile(name)
222 if err != nil {
223 return nil, err
224 }
225
226 // If overlay doesn't exist, return the base (base state irrelevant)
227 if b {
228 return u.base.Open(name)
229 }
230
231 // If overlay is a file, return it (base state irrelevant)
232 dir, err := IsDir(u.layer, name)
233 if err != nil {
234 return nil, err
235 }
236 if !dir {
237 return u.layer.Open(name)
238 }
239
240 // Overlay is a directory, base state now matters.
241 // Base state has 3 states to check but 2 outcomes:
242 // A. It's a file or non-readable in the base (return just the overlay)
243 // B. It's an accessible directory in the base (return a UnionFile)
244
245 // If base is file or nonreadable, return overlay
246 dir, err = IsDir(u.base, name)
247 if !dir || err != nil {
248 return u.layer.Open(name)
249 }
250
251 // Both base & layer are directories
252 // Return union file (if opens are without error)
253 bfile, bErr := u.base.Open(name)
254 lfile, lErr := u.layer.Open(name)
255
256 // If either have errors at this point something is very wrong. Return nil and the errors
257 if bErr != nil || lErr != nil {
258 return nil, fmt.Errorf("BaseErr: %v\nOverlayErr: %v", bErr, lErr)
259 }
260
261 return &UnionFile{Base: bfile, Layer: lfile}, nil
262}
263
264func (u *CopyOnWriteFs) Mkdir(name string, perm os.FileMode) error {
265 dir, err := IsDir(u.base, name)
266 if err != nil {
267 return u.layer.MkdirAll(name, perm)
268 }
269 if dir {
270 return ErrFileExists
271 }
272 return u.layer.MkdirAll(name, perm)
273}
274
275func (u *CopyOnWriteFs) Name() string {
276 return "CopyOnWriteFs"
277}
278
279func (u *CopyOnWriteFs) MkdirAll(name string, perm os.FileMode) error {
280 dir, err := IsDir(u.base, name)
281 if err != nil {
282 return u.layer.MkdirAll(name, perm)
283 }
284 if dir {
285 // This is in line with how os.MkdirAll behaves.
286 return nil
287 }
288 return u.layer.MkdirAll(name, perm)
289}
290
291func (u *CopyOnWriteFs) Create(name string) (File, error) {
292 return u.OpenFile(name, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0666)
293}
diff --git a/vendor/github.com/spf13/afero/go.mod b/vendor/github.com/spf13/afero/go.mod
new file mode 100644
index 0000000..0868550
--- /dev/null
+++ b/vendor/github.com/spf13/afero/go.mod
@@ -0,0 +1,3 @@
1module github.com/spf13/afero
2
3require golang.org/x/text v0.3.0
diff --git a/vendor/github.com/spf13/afero/go.sum b/vendor/github.com/spf13/afero/go.sum
new file mode 100644
index 0000000..6bad37b
--- /dev/null
+++ b/vendor/github.com/spf13/afero/go.sum
@@ -0,0 +1,2 @@
1golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
2golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/vendor/github.com/spf13/afero/httpFs.go b/vendor/github.com/spf13/afero/httpFs.go
new file mode 100644
index 0000000..c421936
--- /dev/null
+++ b/vendor/github.com/spf13/afero/httpFs.go
@@ -0,0 +1,110 @@
1// Copyright © 2014 Steve Francia <spf@spf13.com>.
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// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package afero
15
16import (
17 "errors"
18 "net/http"
19 "os"
20 "path"
21 "path/filepath"
22 "strings"
23 "time"
24)
25
26type httpDir struct {
27 basePath string
28 fs HttpFs
29}
30
31func (d httpDir) Open(name string) (http.File, error) {
32 if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 ||
33 strings.Contains(name, "\x00") {
34 return nil, errors.New("http: invalid character in file path")
35 }
36 dir := string(d.basePath)
37 if dir == "" {
38 dir = "."
39 }
40
41 f, err := d.fs.Open(filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name))))
42 if err != nil {
43 return nil, err
44 }
45 return f, nil
46}
47
48type HttpFs struct {
49 source Fs
50}
51
52func NewHttpFs(source Fs) *HttpFs {
53 return &HttpFs{source: source}
54}
55
56func (h HttpFs) Dir(s string) *httpDir {
57 return &httpDir{basePath: s, fs: h}
58}
59
60func (h HttpFs) Name() string { return "h HttpFs" }
61
62func (h HttpFs) Create(name string) (File, error) {
63 return h.source.Create(name)
64}
65
66func (h HttpFs) Chmod(name string, mode os.FileMode) error {
67 return h.source.Chmod(name, mode)
68}
69
70func (h HttpFs) Chtimes(name string, atime time.Time, mtime time.Time) error {
71 return h.source.Chtimes(name, atime, mtime)
72}
73
74func (h HttpFs) Mkdir(name string, perm os.FileMode) error {
75 return h.source.Mkdir(name, perm)
76}
77
78func (h HttpFs) MkdirAll(path string, perm os.FileMode) error {
79 return h.source.MkdirAll(path, perm)
80}
81
82func (h HttpFs) Open(name string) (http.File, error) {
83 f, err := h.source.Open(name)
84 if err == nil {
85 if httpfile, ok := f.(http.File); ok {
86 return httpfile, nil
87 }
88 }
89 return nil, err
90}
91
92func (h HttpFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
93 return h.source.OpenFile(name, flag, perm)
94}
95
96func (h HttpFs) Remove(name string) error {
97 return h.source.Remove(name)
98}
99
100func (h HttpFs) RemoveAll(path string) error {
101 return h.source.RemoveAll(path)
102}
103
104func (h HttpFs) Rename(oldname, newname string) error {
105 return h.source.Rename(oldname, newname)
106}
107
108func (h HttpFs) Stat(name string) (os.FileInfo, error) {
109 return h.source.Stat(name)
110}
diff --git a/vendor/github.com/spf13/afero/ioutil.go b/vendor/github.com/spf13/afero/ioutil.go
new file mode 100644
index 0000000..5c3a3d8
--- /dev/null
+++ b/vendor/github.com/spf13/afero/ioutil.go
@@ -0,0 +1,230 @@
1// Copyright ©2015 The Go Authors
2// Copyright ©2015 Steve Francia <spf@spf13.com>
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16package afero
17
18import (
19 "bytes"
20 "io"
21 "os"
22 "path/filepath"
23 "sort"
24 "strconv"
25 "sync"
26 "time"
27)
28
29// byName implements sort.Interface.
30type byName []os.FileInfo
31
32func (f byName) Len() int { return len(f) }
33func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
34func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
35
36// ReadDir reads the directory named by dirname and returns
37// a list of sorted directory entries.
38func (a Afero) ReadDir(dirname string) ([]os.FileInfo, error) {
39 return ReadDir(a.Fs, dirname)
40}
41
42func ReadDir(fs Fs, dirname string) ([]os.FileInfo, error) {
43 f, err := fs.Open(dirname)
44 if err != nil {
45 return nil, err
46 }
47 list, err := f.Readdir(-1)
48 f.Close()
49 if err != nil {
50 return nil, err
51 }
52 sort.Sort(byName(list))
53 return list, nil
54}
55
56// ReadFile reads the file named by filename and returns the contents.
57// A successful call returns err == nil, not err == EOF. Because ReadFile
58// reads the whole file, it does not treat an EOF from Read as an error
59// to be reported.
60func (a Afero) ReadFile(filename string) ([]byte, error) {
61 return ReadFile(a.Fs, filename)
62}
63
64func ReadFile(fs Fs, filename string) ([]byte, error) {
65 f, err := fs.Open(filename)
66 if err != nil {
67 return nil, err
68 }
69 defer f.Close()
70 // It's a good but not certain bet that FileInfo will tell us exactly how much to
71 // read, so let's try it but be prepared for the answer to be wrong.
72 var n int64
73
74 if fi, err := f.Stat(); err == nil {
75 // Don't preallocate a huge buffer, just in case.
76 if size := fi.Size(); size < 1e9 {
77 n = size
78 }
79 }
80 // As initial capacity for readAll, use n + a little extra in case Size is zero,
81 // and to avoid another allocation after Read has filled the buffer. The readAll
82 // call will read into its allocated internal buffer cheaply. If the size was
83 // wrong, we'll either waste some space off the end or reallocate as needed, but
84 // in the overwhelmingly common case we'll get it just right.
85 return readAll(f, n+bytes.MinRead)
86}
87
88// readAll reads from r until an error or EOF and returns the data it read
89// from the internal buffer allocated with a specified capacity.
90func readAll(r io.Reader, capacity int64) (b []byte, err error) {
91 buf := bytes.NewBuffer(make([]byte, 0, capacity))
92 // If the buffer overflows, we will get bytes.ErrTooLarge.
93 // Return that as an error. Any other panic remains.
94 defer func() {
95 e := recover()
96 if e == nil {
97 return
98 }
99 if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
100 err = panicErr
101 } else {
102 panic(e)
103 }
104 }()
105 _, err = buf.ReadFrom(r)
106 return buf.Bytes(), err
107}
108
109// ReadAll reads from r until an error or EOF and returns the data it read.
110// A successful call returns err == nil, not err == EOF. Because ReadAll is
111// defined to read from src until EOF, it does not treat an EOF from Read
112// as an error to be reported.
113func ReadAll(r io.Reader) ([]byte, error) {
114 return readAll(r, bytes.MinRead)
115}
116
117// WriteFile writes data to a file named by filename.
118// If the file does not exist, WriteFile creates it with permissions perm;
119// otherwise WriteFile truncates it before writing.
120func (a Afero) WriteFile(filename string, data []byte, perm os.FileMode) error {
121 return WriteFile(a.Fs, filename, data, perm)
122}
123
124func WriteFile(fs Fs, filename string, data []byte, perm os.FileMode) error {
125 f, err := fs.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
126 if err != nil {
127 return err
128 }
129 n, err := f.Write(data)
130 if err == nil && n < len(data) {
131 err = io.ErrShortWrite
132 }
133 if err1 := f.Close(); err == nil {
134 err = err1
135 }
136 return err
137}
138
139// Random number state.
140// We generate random temporary file names so that there's a good
141// chance the file doesn't exist yet - keeps the number of tries in
142// TempFile to a minimum.
143var rand uint32
144var randmu sync.Mutex
145
146func reseed() uint32 {
147 return uint32(time.Now().UnixNano() + int64(os.Getpid()))
148}
149
150func nextSuffix() string {
151 randmu.Lock()
152 r := rand
153 if r == 0 {
154 r = reseed()
155 }
156 r = r*1664525 + 1013904223 // constants from Numerical Recipes
157 rand = r
158 randmu.Unlock()
159 return strconv.Itoa(int(1e9 + r%1e9))[1:]
160}
161
162// TempFile creates a new temporary file in the directory dir
163// with a name beginning with prefix, opens the file for reading
164// and writing, and returns the resulting *File.
165// If dir is the empty string, TempFile uses the default directory
166// for temporary files (see os.TempDir).
167// Multiple programs calling TempFile simultaneously
168// will not choose the same file. The caller can use f.Name()
169// to find the pathname of the file. It is the caller's responsibility
170// to remove the file when no longer needed.
171func (a Afero) TempFile(dir, prefix string) (f File, err error) {
172 return TempFile(a.Fs, dir, prefix)
173}
174
175func TempFile(fs Fs, dir, prefix string) (f File, err error) {
176 if dir == "" {
177 dir = os.TempDir()
178 }
179
180 nconflict := 0
181 for i := 0; i < 10000; i++ {
182 name := filepath.Join(dir, prefix+nextSuffix())
183 f, err = fs.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
184 if os.IsExist(err) {
185 if nconflict++; nconflict > 10 {
186 randmu.Lock()
187 rand = reseed()
188 randmu.Unlock()
189 }
190 continue
191 }
192 break
193 }
194 return
195}
196
197// TempDir creates a new temporary directory in the directory dir
198// with a name beginning with prefix and returns the path of the
199// new directory. If dir is the empty string, TempDir uses the
200// default directory for temporary files (see os.TempDir).
201// Multiple programs calling TempDir simultaneously
202// will not choose the same directory. It is the caller's responsibility
203// to remove the directory when no longer needed.
204func (a Afero) TempDir(dir, prefix string) (name string, err error) {
205 return TempDir(a.Fs, dir, prefix)
206}
207func TempDir(fs Fs, dir, prefix string) (name string, err error) {
208 if dir == "" {
209 dir = os.TempDir()
210 }
211
212 nconflict := 0
213 for i := 0; i < 10000; i++ {
214 try := filepath.Join(dir, prefix+nextSuffix())
215 err = fs.Mkdir(try, 0700)
216 if os.IsExist(err) {
217 if nconflict++; nconflict > 10 {
218 randmu.Lock()
219 rand = reseed()
220 randmu.Unlock()
221 }
222 continue
223 }
224 if err == nil {
225 name = try
226 }
227 break
228 }
229 return
230}
diff --git a/vendor/github.com/spf13/afero/lstater.go b/vendor/github.com/spf13/afero/lstater.go
new file mode 100644
index 0000000..89c1bfc
--- /dev/null
+++ b/vendor/github.com/spf13/afero/lstater.go
@@ -0,0 +1,27 @@
1// Copyright © 2018 Steve Francia <spf@spf13.com>.
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// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package afero
15
16import (
17 "os"
18)
19
20// Lstater is an optional interface in Afero. It is only implemented by the
21// filesystems saying so.
22// It will call Lstat if the filesystem iself is, or it delegates to, the os filesystem.
23// Else it will call Stat.
24// In addtion to the FileInfo, it will return a boolean telling whether Lstat was called or not.
25type Lstater interface {
26 LstatIfPossible(name string) (os.FileInfo, bool, error)
27}
diff --git a/vendor/github.com/spf13/afero/match.go b/vendor/github.com/spf13/afero/match.go
new file mode 100644
index 0000000..c18a87f
--- /dev/null
+++ b/vendor/github.com/spf13/afero/match.go
@@ -0,0 +1,110 @@
1// Copyright © 2014 Steve Francia <spf@spf13.com>.
2// Copyright 2009 The Go Authors. All rights reserved.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
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
15package afero
16
17import (
18 "path/filepath"
19 "sort"
20 "strings"
21)
22
23// Glob returns the names of all files matching pattern or nil
24// if there is no matching file. The syntax of patterns is the same
25// as in Match. The pattern may describe hierarchical names such as
26// /usr/*/bin/ed (assuming the Separator is '/').
27//
28// Glob ignores file system errors such as I/O errors reading directories.
29// The only possible returned error is ErrBadPattern, when pattern
30// is malformed.
31//
32// This was adapted from (http://golang.org/pkg/path/filepath) and uses several
33// built-ins from that package.
34func Glob(fs Fs, pattern string) (matches []string, err error) {
35 if !hasMeta(pattern) {
36 // Lstat not supported by a ll filesystems.
37 if _, err = lstatIfPossible(fs, pattern); err != nil {
38 return nil, nil
39 }
40 return []string{pattern}, nil
41 }
42
43 dir, file := filepath.Split(pattern)
44 switch dir {
45 case "":
46 dir = "."
47 case string(filepath.Separator):
48 // nothing
49 default:
50 dir = dir[0 : len(dir)-1] // chop off trailing separator
51 }
52
53 if !hasMeta(dir) {
54 return glob(fs, dir, file, nil)
55 }
56
57 var m []string
58 m, err = Glob(fs, dir)
59 if err != nil {
60 return
61 }
62 for _, d := range m {
63 matches, err = glob(fs, d, file, matches)
64 if err != nil {
65 return
66 }
67 }
68 return
69}
70
71// glob searches for files matching pattern in the directory dir
72// and appends them to matches. If the directory cannot be
73// opened, it returns the existing matches. New matches are
74// added in lexicographical order.
75func glob(fs Fs, dir, pattern string, matches []string) (m []string, e error) {
76 m = matches
77 fi, err := fs.Stat(dir)
78 if err != nil {
79 return
80 }
81 if !fi.IsDir() {
82 return
83 }
84 d, err := fs.Open(dir)
85 if err != nil {
86 return
87 }
88 defer d.Close()
89
90 names, _ := d.Readdirnames(-1)
91 sort.Strings(names)
92
93 for _, n := range names {
94 matched, err := filepath.Match(pattern, n)
95 if err != nil {
96 return m, err
97 }
98 if matched {
99 m = append(m, filepath.Join(dir, n))
100 }
101 }
102 return
103}
104
105// hasMeta reports whether path contains any of the magic characters
106// recognized by Match.
107func hasMeta(path string) bool {
108 // TODO(niemeyer): Should other magic characters be added here?
109 return strings.IndexAny(path, "*?[") >= 0
110}
diff --git a/vendor/github.com/spf13/afero/mem/dir.go b/vendor/github.com/spf13/afero/mem/dir.go
new file mode 100644
index 0000000..e104013
--- /dev/null
+++ b/vendor/github.com/spf13/afero/mem/dir.go
@@ -0,0 +1,37 @@
1// Copyright © 2014 Steve Francia <spf@spf13.com>.
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// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package mem
15
16type Dir interface {
17 Len() int
18 Names() []string
19 Files() []*FileData
20 Add(*FileData)
21 Remove(*FileData)
22}
23
24func RemoveFromMemDir(dir *FileData, f *FileData) {
25 dir.memDir.Remove(f)
26}
27
28func AddToMemDir(dir *FileData, f *FileData) {
29 dir.memDir.Add(f)
30}
31
32func InitializeDir(d *FileData) {
33 if d.memDir == nil {
34 d.dir = true
35 d.memDir = &DirMap{}
36 }
37}
diff --git a/vendor/github.com/spf13/afero/mem/dirmap.go b/vendor/github.com/spf13/afero/mem/dirmap.go
new file mode 100644
index 0000000..03a57ee
--- /dev/null
+++ b/vendor/github.com/spf13/afero/mem/dirmap.go
@@ -0,0 +1,43 @@
1// Copyright © 2015 Steve Francia <spf@spf13.com>.
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// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package mem
15
16import "sort"
17
18type DirMap map[string]*FileData
19
20func (m DirMap) Len() int { return len(m) }
21func (m DirMap) Add(f *FileData) { m[f.name] = f }
22func (m DirMap) Remove(f *FileData) { delete(m, f.name) }
23func (m DirMap) Files() (files []*FileData) {
24 for _, f := range m {
25 files = append(files, f)
26 }
27 sort.Sort(filesSorter(files))
28 return files
29}
30
31// implement sort.Interface for []*FileData
32type filesSorter []*FileData
33
34func (s filesSorter) Len() int { return len(s) }
35func (s filesSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
36func (s filesSorter) Less(i, j int) bool { return s[i].name < s[j].name }
37
38func (m DirMap) Names() (names []string) {
39 for x := range m {
40 names = append(names, x)
41 }
42 return names
43}
diff --git a/vendor/github.com/spf13/afero/mem/file.go b/vendor/github.com/spf13/afero/mem/file.go
new file mode 100644
index 0000000..7af2fb5
--- /dev/null
+++ b/vendor/github.com/spf13/afero/mem/file.go
@@ -0,0 +1,317 @@
1// Copyright © 2015 Steve Francia <spf@spf13.com>.
2// Copyright 2013 tsuru authors. All rights reserved.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
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
15package mem
16
17import (
18 "bytes"
19 "errors"
20 "io"
21 "os"
22 "path/filepath"
23 "sync"
24 "sync/atomic"
25)
26
27import "time"
28
29const FilePathSeparator = string(filepath.Separator)
30
31type File struct {
32 // atomic requires 64-bit alignment for struct field access
33 at int64
34 readDirCount int64
35 closed bool
36 readOnly bool
37 fileData *FileData
38}
39
40func NewFileHandle(data *FileData) *File {
41 return &File{fileData: data}
42}
43
44func NewReadOnlyFileHandle(data *FileData) *File {
45 return &File{fileData: data, readOnly: true}
46}
47
48func (f File) Data() *FileData {
49 return f.fileData
50}
51
52type FileData struct {
53 sync.Mutex
54 name string
55 data []byte
56 memDir Dir
57 dir bool
58 mode os.FileMode
59 modtime time.Time
60}
61
62func (d *FileData) Name() string {
63 d.Lock()
64 defer d.Unlock()
65 return d.name
66}
67
68func CreateFile(name string) *FileData {
69 return &FileData{name: name, mode: os.ModeTemporary, modtime: time.Now()}
70}
71
72func CreateDir(name string) *FileData {
73 return &FileData{name: name, memDir: &DirMap{}, dir: true}
74}
75
76func ChangeFileName(f *FileData, newname string) {
77 f.Lock()
78 f.name = newname
79 f.Unlock()
80}
81
82func SetMode(f *FileData, mode os.FileMode) {
83 f.Lock()
84 f.mode = mode
85 f.Unlock()
86}
87
88func SetModTime(f *FileData, mtime time.Time) {
89 f.Lock()
90 setModTime(f, mtime)
91 f.Unlock()
92}
93
94func setModTime(f *FileData, mtime time.Time) {
95 f.modtime = mtime
96}
97
98func GetFileInfo(f *FileData) *FileInfo {
99 return &FileInfo{f}
100}
101
102func (f *File) Open() error {
103 atomic.StoreInt64(&f.at, 0)
104 atomic.StoreInt64(&f.readDirCount, 0)
105 f.fileData.Lock()
106 f.closed = false
107 f.fileData.Unlock()
108 return nil
109}
110
111func (f *File) Close() error {
112 f.fileData.Lock()
113 f.closed = true
114 if !f.readOnly {
115 setModTime(f.fileData, time.Now())
116 }
117 f.fileData.Unlock()
118 return nil
119}
120
121func (f *File) Name() string {
122 return f.fileData.Name()
123}
124
125func (f *File) Stat() (os.FileInfo, error) {
126 return &FileInfo{f.fileData}, nil
127}
128
129func (f *File) Sync() error {
130 return nil
131}
132
133func (f *File) Readdir(count int) (res []os.FileInfo, err error) {
134 if !f.fileData.dir {
135 return nil, &os.PathError{Op: "readdir", Path: f.fileData.name, Err: errors.New("not a dir")}
136 }
137 var outLength int64
138
139 f.fileData.Lock()
140 files := f.fileData.memDir.Files()[f.readDirCount:]
141 if count > 0 {
142 if len(files) < count {
143 outLength = int64(len(files))
144 } else {
145 outLength = int64(count)
146 }
147 if len(files) == 0 {
148 err = io.EOF
149 }
150 } else {
151 outLength = int64(len(files))
152 }
153 f.readDirCount += outLength
154 f.fileData.Unlock()
155
156 res = make([]os.FileInfo, outLength)
157 for i := range res {
158 res[i] = &FileInfo{files[i]}
159 }
160
161 return res, err
162}
163
164func (f *File) Readdirnames(n int) (names []string, err error) {
165 fi, err := f.Readdir(n)
166 names = make([]string, len(fi))
167 for i, f := range fi {
168 _, names[i] = filepath.Split(f.Name())
169 }
170 return names, err
171}
172
173func (f *File) Read(b []byte) (n int, err error) {
174 f.fileData.Lock()
175 defer f.fileData.Unlock()
176 if f.closed == true {
177 return 0, ErrFileClosed
178 }
179 if len(b) > 0 && int(f.at) == len(f.fileData.data) {
180 return 0, io.EOF
181 }
182 if int(f.at) > len(f.fileData.data) {
183 return 0, io.ErrUnexpectedEOF
184 }
185 if len(f.fileData.data)-int(f.at) >= len(b) {
186 n = len(b)
187 } else {
188 n = len(f.fileData.data) - int(f.at)
189 }
190 copy(b, f.fileData.data[f.at:f.at+int64(n)])
191 atomic.AddInt64(&f.at, int64(n))
192 return
193}
194
195func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
196 atomic.StoreInt64(&f.at, off)
197 return f.Read(b)
198}
199
200func (f *File) Truncate(size int64) error {
201 if f.closed == true {
202 return ErrFileClosed
203 }
204 if f.readOnly {
205 return &os.PathError{Op: "truncate", Path: f.fileData.name, Err: errors.New("file handle is read only")}
206 }
207 if size < 0 {
208 return ErrOutOfRange
209 }
210 if size > int64(len(f.fileData.data)) {
211 diff := size - int64(len(f.fileData.data))
212 f.fileData.data = append(f.fileData.data, bytes.Repeat([]byte{00}, int(diff))...)
213 } else {
214 f.fileData.data = f.fileData.data[0:size]
215 }
216 setModTime(f.fileData, time.Now())
217 return nil
218}
219
220func (f *File) Seek(offset int64, whence int) (int64, error) {
221 if f.closed == true {
222 return 0, ErrFileClosed
223 }
224 switch whence {
225 case 0:
226 atomic.StoreInt64(&f.at, offset)
227 case 1:
228 atomic.AddInt64(&f.at, int64(offset))
229 case 2:
230 atomic.StoreInt64(&f.at, int64(len(f.fileData.data))+offset)
231 }
232 return f.at, nil
233}
234
235func (f *File) Write(b []byte) (n int, err error) {
236 if f.readOnly {
237 return 0, &os.PathError{Op: "write", Path: f.fileData.name, Err: errors.New("file handle is read only")}
238 }
239 n = len(b)
240 cur := atomic.LoadInt64(&f.at)
241 f.fileData.Lock()
242 defer f.fileData.Unlock()
243 diff := cur - int64(len(f.fileData.data))
244 var tail []byte
245 if n+int(cur) < len(f.fileData.data) {
246 tail = f.fileData.data[n+int(cur):]
247 }
248 if diff > 0 {
249 f.fileData.data = append(bytes.Repeat([]byte{00}, int(diff)), b...)
250 f.fileData.data = append(f.fileData.data, tail...)
251 } else {
252 f.fileData.data = append(f.fileData.data[:cur], b...)
253 f.fileData.data = append(f.fileData.data, tail...)
254 }
255 setModTime(f.fileData, time.Now())
256
257 atomic.StoreInt64(&f.at, int64(len(f.fileData.data)))
258 return
259}
260
261func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
262 atomic.StoreInt64(&f.at, off)
263 return f.Write(b)
264}
265
266func (f *File) WriteString(s string) (ret int, err error) {
267 return f.Write([]byte(s))
268}
269
270func (f *File) Info() *FileInfo {
271 return &FileInfo{f.fileData}
272}
273
274type FileInfo struct {
275 *FileData
276}
277
278// Implements os.FileInfo
279func (s *FileInfo) Name() string {
280 s.Lock()
281 _, name := filepath.Split(s.name)
282 s.Unlock()
283 return name
284}
285func (s *FileInfo) Mode() os.FileMode {
286 s.Lock()
287 defer s.Unlock()
288 return s.mode
289}
290func (s *FileInfo) ModTime() time.Time {
291 s.Lock()
292 defer s.Unlock()
293 return s.modtime
294}
295func (s *FileInfo) IsDir() bool {
296 s.Lock()
297 defer s.Unlock()
298 return s.dir
299}
300func (s *FileInfo) Sys() interface{} { return nil }
301func (s *FileInfo) Size() int64 {
302 if s.IsDir() {
303 return int64(42)
304 }
305 s.Lock()
306 defer s.Unlock()
307 return int64(len(s.data))
308}
309
310var (
311 ErrFileClosed = errors.New("File is closed")
312 ErrOutOfRange = errors.New("Out of range")
313 ErrTooLarge = errors.New("Too large")
314 ErrFileNotFound = os.ErrNotExist
315 ErrFileExists = os.ErrExist
316 ErrDestinationExists = os.ErrExist
317)
diff --git a/vendor/github.com/spf13/afero/memmap.go b/vendor/github.com/spf13/afero/memmap.go
new file mode 100644
index 0000000..09498e7
--- /dev/null
+++ b/vendor/github.com/spf13/afero/memmap.go
@@ -0,0 +1,365 @@
1// Copyright © 2014 Steve Francia <spf@spf13.com>.
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// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package afero
15
16import (
17 "fmt"
18 "log"
19 "os"
20 "path/filepath"
21 "strings"
22 "sync"
23 "time"
24
25 "github.com/spf13/afero/mem"
26)
27
28type MemMapFs struct {
29 mu sync.RWMutex
30 data map[string]*mem.FileData
31 init sync.Once
32}
33
34func NewMemMapFs() Fs {
35 return &MemMapFs{}
36}
37
38func (m *MemMapFs) getData() map[string]*mem.FileData {
39 m.init.Do(func() {
40 m.data = make(map[string]*mem.FileData)
41 // Root should always exist, right?
42 // TODO: what about windows?
43 m.data[FilePathSeparator] = mem.CreateDir(FilePathSeparator)
44 })
45 return m.data
46}
47
48func (*MemMapFs) Name() string { return "MemMapFS" }
49
50func (m *MemMapFs) Create(name string) (File, error) {
51 name = normalizePath(name)
52 m.mu.Lock()
53 file := mem.CreateFile(name)
54 m.getData()[name] = file
55 m.registerWithParent(file)
56 m.mu.Unlock()
57 return mem.NewFileHandle(file), nil
58}
59
60func (m *MemMapFs) unRegisterWithParent(fileName string) error {
61 f, err := m.lockfreeOpen(fileName)
62 if err != nil {
63 return err
64 }
65 parent := m.findParent(f)
66 if parent == nil {
67 log.Panic("parent of ", f.Name(), " is nil")
68 }
69
70 parent.Lock()
71 mem.RemoveFromMemDir(parent, f)
72 parent.Unlock()
73 return nil
74}
75
76func (m *MemMapFs) findParent(f *mem.FileData) *mem.FileData {
77 pdir, _ := filepath.Split(f.Name())
78 pdir = filepath.Clean(pdir)
79 pfile, err := m.lockfreeOpen(pdir)
80 if err != nil {
81 return nil
82 }
83 return pfile
84}
85
86func (m *MemMapFs) registerWithParent(f *mem.FileData) {
87 if f == nil {
88 return
89 }
90 parent := m.findParent(f)
91 if parent == nil {
92 pdir := filepath.Dir(filepath.Clean(f.Name()))
93 err := m.lockfreeMkdir(pdir, 0777)
94 if err != nil {
95 //log.Println("Mkdir error:", err)
96 return
97 }
98 parent, err = m.lockfreeOpen(pdir)
99 if err != nil {
100 //log.Println("Open after Mkdir error:", err)
101 return
102 }
103 }
104
105 parent.Lock()
106 mem.InitializeDir(parent)
107 mem.AddToMemDir(parent, f)
108 parent.Unlock()
109}
110
111func (m *MemMapFs) lockfreeMkdir(name string, perm os.FileMode) error {
112 name = normalizePath(name)
113 x, ok := m.getData()[name]
114 if ok {
115 // Only return ErrFileExists if it's a file, not a directory.
116 i := mem.FileInfo{FileData: x}
117 if !i.IsDir() {
118 return ErrFileExists
119 }
120 } else {
121 item := mem.CreateDir(name)
122 m.getData()[name] = item
123 m.registerWithParent(item)
124 }
125 return nil
126}
127
128func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error {
129 name = normalizePath(name)
130
131 m.mu.RLock()
132 _, ok := m.getData()[name]
133 m.mu.RUnlock()
134 if ok {
135 return &os.PathError{Op: "mkdir", Path: name, Err: ErrFileExists}
136 }
137
138 m.mu.Lock()
139 item := mem.CreateDir(name)
140 m.getData()[name] = item
141 m.registerWithParent(item)
142 m.mu.Unlock()
143
144 m.Chmod(name, perm|os.ModeDir)
145
146 return nil
147}
148
149func (m *MemMapFs) MkdirAll(path string, perm os.FileMode) error {
150 err := m.Mkdir(path, perm)
151 if err != nil {
152 if err.(*os.PathError).Err == ErrFileExists {
153 return nil
154 }
155 return err
156 }
157 return nil
158}
159
160// Handle some relative paths
161func normalizePath(path string) string {
162 path = filepath.Clean(path)
163
164 switch path {
165 case ".":
166 return FilePathSeparator
167 case "..":
168 return FilePathSeparator
169 default:
170 return path
171 }
172}
173
174func (m *MemMapFs) Open(name string) (File, error) {
175 f, err := m.open(name)
176 if f != nil {
177 return mem.NewReadOnlyFileHandle(f), err
178 }
179 return nil, err
180}
181
182func (m *MemMapFs) openWrite(name string) (File, error) {
183 f, err := m.open(name)
184 if f != nil {
185 return mem.NewFileHandle(f), err
186 }
187 return nil, err
188}
189
190func (m *MemMapFs) open(name string) (*mem.FileData, error) {
191 name = normalizePath(name)
192
193 m.mu.RLock()
194 f, ok := m.getData()[name]
195 m.mu.RUnlock()
196 if !ok {
197 return nil, &os.PathError{Op: "open", Path: name, Err: ErrFileNotFound}
198 }
199 return f, nil
200}
201
202func (m *MemMapFs) lockfreeOpen(name string) (*mem.FileData, error) {
203 name = normalizePath(name)
204 f, ok := m.getData()[name]
205 if ok {
206 return f, nil
207 } else {
208 return nil, ErrFileNotFound
209 }
210}
211
212func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
213 chmod := false
214 file, err := m.openWrite(name)
215 if os.IsNotExist(err) && (flag&os.O_CREATE > 0) {
216 file, err = m.Create(name)
217 chmod = true
218 }
219 if err != nil {
220 return nil, err
221 }
222 if flag == os.O_RDONLY {
223 file = mem.NewReadOnlyFileHandle(file.(*mem.File).Data())
224 }
225 if flag&os.O_APPEND > 0 {
226 _, err = file.Seek(0, os.SEEK_END)
227 if err != nil {
228 file.Close()
229 return nil, err
230 }
231 }
232 if flag&os.O_TRUNC > 0 && flag&(os.O_RDWR|os.O_WRONLY) > 0 {
233 err = file.Truncate(0)
234 if err != nil {
235 file.Close()
236 return nil, err
237 }
238 }
239 if chmod {
240 m.Chmod(name, perm)
241 }
242 return file, nil
243}
244
245func (m *MemMapFs) Remove(name string) error {
246 name = normalizePath(name)
247
248 m.mu.Lock()
249 defer m.mu.Unlock()
250
251 if _, ok := m.getData()[name]; ok {
252 err := m.unRegisterWithParent(name)
253 if err != nil {
254 return &os.PathError{Op: "remove", Path: name, Err: err}
255 }
256 delete(m.getData(), name)
257 } else {
258 return &os.PathError{Op: "remove", Path: name, Err: os.ErrNotExist}
259 }
260 return nil
261}
262
263func (m *MemMapFs) RemoveAll(path string) error {
264 path = normalizePath(path)
265 m.mu.Lock()
266 m.unRegisterWithParent(path)
267 m.mu.Unlock()
268
269 m.mu.RLock()
270 defer m.mu.RUnlock()
271
272 for p, _ := range m.getData() {
273 if strings.HasPrefix(p, path) {
274 m.mu.RUnlock()
275 m.mu.Lock()
276 delete(m.getData(), p)
277 m.mu.Unlock()
278 m.mu.RLock()
279 }
280 }
281 return nil
282}
283
284func (m *MemMapFs) Rename(oldname, newname string) error {
285 oldname = normalizePath(oldname)
286 newname = normalizePath(newname)
287
288 if oldname == newname {
289 return nil
290 }
291
292 m.mu.RLock()
293 defer m.mu.RUnlock()
294 if _, ok := m.getData()[oldname]; ok {
295 m.mu.RUnlock()
296 m.mu.Lock()
297 m.unRegisterWithParent(oldname)
298 fileData := m.getData()[oldname]
299 delete(m.getData(), oldname)
300 mem.ChangeFileName(fileData, newname)
301 m.getData()[newname] = fileData
302 m.registerWithParent(fileData)
303 m.mu.Unlock()
304 m.mu.RLock()
305 } else {
306 return &os.PathError{Op: "rename", Path: oldname, Err: ErrFileNotFound}
307 }
308 return nil
309}
310
311func (m *MemMapFs) Stat(name string) (os.FileInfo, error) {
312 f, err := m.Open(name)
313 if err != nil {
314 return nil, err
315 }
316 fi := mem.GetFileInfo(f.(*mem.File).Data())
317 return fi, nil
318}
319
320func (m *MemMapFs) Chmod(name string, mode os.FileMode) error {
321 name = normalizePath(name)
322
323 m.mu.RLock()
324 f, ok := m.getData()[name]
325 m.mu.RUnlock()
326 if !ok {
327 return &os.PathError{Op: "chmod", Path: name, Err: ErrFileNotFound}
328 }
329
330 m.mu.Lock()
331 mem.SetMode(f, mode)
332 m.mu.Unlock()
333
334 return nil
335}
336
337func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error {
338 name = normalizePath(name)
339
340 m.mu.RLock()
341 f, ok := m.getData()[name]
342 m.mu.RUnlock()
343 if !ok {
344 return &os.PathError{Op: "chtimes", Path: name, Err: ErrFileNotFound}
345 }
346
347 m.mu.Lock()
348 mem.SetModTime(f, mtime)
349 m.mu.Unlock()
350
351 return nil
352}
353
354func (m *MemMapFs) List() {
355 for _, x := range m.data {
356 y := mem.FileInfo{FileData: x}
357 fmt.Println(x.Name(), y.Size())
358 }
359}
360
361// func debugMemMapList(fs Fs) {
362// if x, ok := fs.(*MemMapFs); ok {
363// x.List()
364// }
365// }
diff --git a/vendor/github.com/spf13/afero/os.go b/vendor/github.com/spf13/afero/os.go
new file mode 100644
index 0000000..13cc1b8
--- /dev/null
+++ b/vendor/github.com/spf13/afero/os.go
@@ -0,0 +1,101 @@
1// Copyright © 2014 Steve Francia <spf@spf13.com>.
2// Copyright 2013 tsuru authors. All rights reserved.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
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
15package afero
16
17import (
18 "os"
19 "time"
20)
21
22var _ Lstater = (*OsFs)(nil)
23
24// OsFs is a Fs implementation that uses functions provided by the os package.
25//
26// For details in any method, check the documentation of the os package
27// (http://golang.org/pkg/os/).
28type OsFs struct{}
29
30func NewOsFs() Fs {
31 return &OsFs{}
32}
33
34func (OsFs) Name() string { return "OsFs" }
35
36func (OsFs) Create(name string) (File, error) {
37 f, e := os.Create(name)
38 if f == nil {
39 // while this looks strange, we need to return a bare nil (of type nil) not
40 // a nil value of type *os.File or nil won't be nil
41 return nil, e
42 }
43 return f, e
44}
45
46func (OsFs) Mkdir(name string, perm os.FileMode) error {
47 return os.Mkdir(name, perm)
48}
49
50func (OsFs) MkdirAll(path string, perm os.FileMode) error {
51 return os.MkdirAll(path, perm)
52}
53
54func (OsFs) Open(name string) (File, error) {
55 f, e := os.Open(name)
56 if f == nil {
57 // while this looks strange, we need to return a bare nil (of type nil) not
58 // a nil value of type *os.File or nil won't be nil
59 return nil, e
60 }
61 return f, e
62}
63
64func (OsFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
65 f, e := os.OpenFile(name, flag, perm)
66 if f == nil {
67 // while this looks strange, we need to return a bare nil (of type nil) not
68 // a nil value of type *os.File or nil won't be nil
69 return nil, e
70 }
71 return f, e
72}
73
74func (OsFs) Remove(name string) error {
75 return os.Remove(name)
76}
77
78func (OsFs) RemoveAll(path string) error {
79 return os.RemoveAll(path)
80}
81
82func (OsFs) Rename(oldname, newname string) error {
83 return os.Rename(oldname, newname)
84}
85
86func (OsFs) Stat(name string) (os.FileInfo, error) {
87 return os.Stat(name)
88}
89
90func (OsFs) Chmod(name string, mode os.FileMode) error {
91 return os.Chmod(name, mode)
92}
93
94func (OsFs) Chtimes(name string, atime time.Time, mtime time.Time) error {
95 return os.Chtimes(name, atime, mtime)
96}
97
98func (OsFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
99 fi, err := os.Lstat(name)
100 return fi, true, err
101}
diff --git a/vendor/github.com/spf13/afero/path.go b/vendor/github.com/spf13/afero/path.go
new file mode 100644
index 0000000..18f60a0
--- /dev/null
+++ b/vendor/github.com/spf13/afero/path.go
@@ -0,0 +1,106 @@
1// Copyright ©2015 The Go Authors
2// Copyright ©2015 Steve Francia <spf@spf13.com>
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16package afero
17
18import (
19 "os"
20 "path/filepath"
21 "sort"
22)
23
24// readDirNames reads the directory named by dirname and returns
25// a sorted list of directory entries.
26// adapted from https://golang.org/src/path/filepath/path.go
27func readDirNames(fs Fs, dirname string) ([]string, error) {
28 f, err := fs.Open(dirname)
29 if err != nil {
30 return nil, err
31 }
32 names, err := f.Readdirnames(-1)
33 f.Close()
34 if err != nil {
35 return nil, err
36 }
37 sort.Strings(names)
38 return names, nil
39}
40
41// walk recursively descends path, calling walkFn
42// adapted from https://golang.org/src/path/filepath/path.go
43func walk(fs Fs, path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
44 err := walkFn(path, info, nil)
45 if err != nil {
46 if info.IsDir() && err == filepath.SkipDir {
47 return nil
48 }
49 return err
50 }
51
52 if !info.IsDir() {
53 return nil
54 }
55
56 names, err := readDirNames(fs, path)
57 if err != nil {
58 return walkFn(path, info, err)
59 }
60
61 for _, name := range names {
62 filename := filepath.Join(path, name)
63 fileInfo, err := lstatIfPossible(fs, filename)
64 if err != nil {
65 if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
66 return err
67 }
68 } else {
69 err = walk(fs, filename, fileInfo, walkFn)
70 if err != nil {
71 if !fileInfo.IsDir() || err != filepath.SkipDir {
72 return err
73 }
74 }
75 }
76 }
77 return nil
78}
79
80// if the filesystem supports it, use Lstat, else use fs.Stat
81func lstatIfPossible(fs Fs, path string) (os.FileInfo, error) {
82 if lfs, ok := fs.(Lstater); ok {
83 fi, _, err := lfs.LstatIfPossible(path)
84 return fi, err
85 }
86 return fs.Stat(path)
87}
88
89// Walk walks the file tree rooted at root, calling walkFn for each file or
90// directory in the tree, including root. All errors that arise visiting files
91// and directories are filtered by walkFn. The files are walked in lexical
92// order, which makes the output deterministic but means that for very
93// large directories Walk can be inefficient.
94// Walk does not follow symbolic links.
95
96func (a Afero) Walk(root string, walkFn filepath.WalkFunc) error {
97 return Walk(a.Fs, root, walkFn)
98}
99
100func Walk(fs Fs, root string, walkFn filepath.WalkFunc) error {
101 info, err := lstatIfPossible(fs, root)
102 if err != nil {
103 return walkFn(root, nil, err)
104 }
105 return walk(fs, root, info, walkFn)
106}
diff --git a/vendor/github.com/spf13/afero/readonlyfs.go b/vendor/github.com/spf13/afero/readonlyfs.go
new file mode 100644
index 0000000..c6376ec
--- /dev/null
+++ b/vendor/github.com/spf13/afero/readonlyfs.go
@@ -0,0 +1,80 @@
1package afero
2
3import (
4 "os"
5 "syscall"
6 "time"
7)
8
9var _ Lstater = (*ReadOnlyFs)(nil)
10
11type ReadOnlyFs struct {
12 source Fs
13}
14
15func NewReadOnlyFs(source Fs) Fs {
16 return &ReadOnlyFs{source: source}
17}
18
19func (r *ReadOnlyFs) ReadDir(name string) ([]os.FileInfo, error) {
20 return ReadDir(r.source, name)
21}
22
23func (r *ReadOnlyFs) Chtimes(n string, a, m time.Time) error {
24 return syscall.EPERM
25}
26
27func (r *ReadOnlyFs) Chmod(n string, m os.FileMode) error {
28 return syscall.EPERM
29}
30
31func (r *ReadOnlyFs) Name() string {
32 return "ReadOnlyFilter"
33}
34
35func (r *ReadOnlyFs) Stat(name string) (os.FileInfo, error) {
36 return r.source.Stat(name)
37}
38
39func (r *ReadOnlyFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
40 if lsf, ok := r.source.(Lstater); ok {
41 return lsf.LstatIfPossible(name)
42 }
43 fi, err := r.Stat(name)
44 return fi, false, err
45}
46
47func (r *ReadOnlyFs) Rename(o, n string) error {
48 return syscall.EPERM
49}
50
51func (r *ReadOnlyFs) RemoveAll(p string) error {
52 return syscall.EPERM
53}
54
55func (r *ReadOnlyFs) Remove(n string) error {
56 return syscall.EPERM
57}
58
59func (r *ReadOnlyFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
60 if flag&(os.O_WRONLY|syscall.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 {
61 return nil, syscall.EPERM
62 }
63 return r.source.OpenFile(name, flag, perm)
64}
65
66func (r *ReadOnlyFs) Open(n string) (File, error) {
67 return r.source.Open(n)
68}
69
70func (r *ReadOnlyFs) Mkdir(n string, p os.FileMode) error {
71 return syscall.EPERM
72}
73
74func (r *ReadOnlyFs) MkdirAll(n string, p os.FileMode) error {
75 return syscall.EPERM
76}
77
78func (r *ReadOnlyFs) Create(n string) (File, error) {
79 return nil, syscall.EPERM
80}
diff --git a/vendor/github.com/spf13/afero/regexpfs.go b/vendor/github.com/spf13/afero/regexpfs.go
new file mode 100644
index 0000000..9d92dbc
--- /dev/null
+++ b/vendor/github.com/spf13/afero/regexpfs.go
@@ -0,0 +1,214 @@
1package afero
2
3import (
4 "os"
5 "regexp"
6 "syscall"
7 "time"
8)
9
10// The RegexpFs filters files (not directories) by regular expression. Only
11// files matching the given regexp will be allowed, all others get a ENOENT error (
12// "No such file or directory").
13//
14type RegexpFs struct {
15 re *regexp.Regexp
16 source Fs
17}
18
19func NewRegexpFs(source Fs, re *regexp.Regexp) Fs {
20 return &RegexpFs{source: source, re: re}
21}
22
23type RegexpFile struct {
24 f File
25 re *regexp.Regexp
26}
27
28func (r *RegexpFs) matchesName(name string) error {
29 if r.re == nil {
30 return nil
31 }
32 if r.re.MatchString(name) {
33 return nil
34 }
35 return syscall.ENOENT
36}
37
38func (r *RegexpFs) dirOrMatches(name string) error {
39 dir, err := IsDir(r.source, name)
40 if err != nil {
41 return err
42 }
43 if dir {
44 return nil
45 }
46 return r.matchesName(name)
47}
48
49func (r *RegexpFs) Chtimes(name string, a, m time.Time) error {
50 if err := r.dirOrMatches(name); err != nil {
51 return err
52 }
53 return r.source.Chtimes(name, a, m)
54}
55
56func (r *RegexpFs) Chmod(name string, mode os.FileMode) error {
57 if err := r.dirOrMatches(name); err != nil {
58 return err
59 }
60 return r.source.Chmod(name, mode)
61}
62
63func (r *RegexpFs) Name() string {
64 return "RegexpFs"
65}
66
67func (r *RegexpFs) Stat(name string) (os.FileInfo, error) {
68 if err := r.dirOrMatches(name); err != nil {
69 return nil, err
70 }
71 return r.source.Stat(name)
72}
73
74func (r *RegexpFs) Rename(oldname, newname string) error {
75 dir, err := IsDir(r.source, oldname)
76 if err != nil {
77 return err
78 }
79 if dir {
80 return nil
81 }
82 if err := r.matchesName(oldname); err != nil {
83 return err
84 }
85 if err := r.matchesName(newname); err != nil {
86 return err
87 }
88 return r.source.Rename(oldname, newname)
89}
90
91func (r *RegexpFs) RemoveAll(p string) error {
92 dir, err := IsDir(r.source, p)
93 if err != nil {
94 return err
95 }
96 if !dir {
97 if err := r.matchesName(p); err != nil {
98 return err
99 }
100 }
101 return r.source.RemoveAll(p)
102}
103
104func (r *RegexpFs) Remove(name string) error {
105 if err := r.dirOrMatches(name); err != nil {
106 return err
107 }
108 return r.source.Remove(name)
109}
110
111func (r *RegexpFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
112 if err := r.dirOrMatches(name); err != nil {
113 return nil, err
114 }
115 return r.source.OpenFile(name, flag, perm)
116}
117
118func (r *RegexpFs) Open(name string) (File, error) {
119 dir, err := IsDir(r.source, name)
120 if err != nil {
121 return nil, err
122 }
123 if !dir {
124 if err := r.matchesName(name); err != nil {
125 return nil, err
126 }
127 }
128 f, err := r.source.Open(name)
129 return &RegexpFile{f: f, re: r.re}, nil
130}
131
132func (r *RegexpFs) Mkdir(n string, p os.FileMode) error {
133 return r.source.Mkdir(n, p)
134}
135
136func (r *RegexpFs) MkdirAll(n string, p os.FileMode) error {
137 return r.source.MkdirAll(n, p)
138}
139
140func (r *RegexpFs) Create(name string) (File, error) {
141 if err := r.matchesName(name); err != nil {
142 return nil, err
143 }
144 return r.source.Create(name)
145}
146
147func (f *RegexpFile) Close() error {
148 return f.f.Close()
149}
150
151func (f *RegexpFile) Read(s []byte) (int, error) {
152 return f.f.Read(s)
153}
154
155func (f *RegexpFile) ReadAt(s []byte, o int64) (int, error) {
156 return f.f.ReadAt(s, o)
157}
158
159func (f *RegexpFile) Seek(o int64, w int) (int64, error) {
160 return f.f.Seek(o, w)
161}
162
163func (f *RegexpFile) Write(s []byte) (int, error) {
164 return f.f.Write(s)
165}
166
167func (f *RegexpFile) WriteAt(s []byte, o int64) (int, error) {
168 return f.f.WriteAt(s, o)
169}
170
171func (f *RegexpFile) Name() string {
172 return f.f.Name()
173}
174
175func (f *RegexpFile) Readdir(c int) (fi []os.FileInfo, err error) {
176 var rfi []os.FileInfo
177 rfi, err = f.f.Readdir(c)
178 if err != nil {
179 return nil, err
180 }
181 for _, i := range rfi {
182 if i.IsDir() || f.re.MatchString(i.Name()) {
183 fi = append(fi, i)
184 }
185 }
186 return fi, nil
187}
188
189func (f *RegexpFile) Readdirnames(c int) (n []string, err error) {
190 fi, err := f.Readdir(c)
191 if err != nil {
192 return nil, err
193 }
194 for _, s := range fi {
195 n = append(n, s.Name())
196 }
197 return n, nil
198}
199
200func (f *RegexpFile) Stat() (os.FileInfo, error) {
201 return f.f.Stat()
202}
203
204func (f *RegexpFile) Sync() error {
205 return f.f.Sync()
206}
207
208func (f *RegexpFile) Truncate(s int64) error {
209 return f.f.Truncate(s)
210}
211
212func (f *RegexpFile) WriteString(s string) (int, error) {
213 return f.f.WriteString(s)
214}
diff --git a/vendor/github.com/spf13/afero/unionFile.go b/vendor/github.com/spf13/afero/unionFile.go
new file mode 100644
index 0000000..abcf12d
--- /dev/null
+++ b/vendor/github.com/spf13/afero/unionFile.go
@@ -0,0 +1,316 @@
1package afero
2
3import (
4 "io"
5 "os"
6 "path/filepath"
7 "syscall"
8)
9
10// The UnionFile implements the afero.File interface and will be returned
11// when reading a directory present at least in the overlay or opening a file
12// for writing.
13//
14// The calls to
15// Readdir() and Readdirnames() merge the file os.FileInfo / names from the
16// base and the overlay - for files present in both layers, only those
17// from the overlay will be used.
18//
19// When opening files for writing (Create() / OpenFile() with the right flags)
20// the operations will be done in both layers, starting with the overlay. A
21// successful read in the overlay will move the cursor position in the base layer
22// by the number of bytes read.
23type UnionFile struct {
24 Base File
25 Layer File
26 Merger DirsMerger
27 off int
28 files []os.FileInfo
29}
30
31func (f *UnionFile) Close() error {
32 // first close base, so we have a newer timestamp in the overlay. If we'd close
33 // the overlay first, we'd get a cacheStale the next time we access this file
34 // -> cache would be useless ;-)
35 if f.Base != nil {
36 f.Base.Close()
37 }
38 if f.Layer != nil {
39 return f.Layer.Close()
40 }
41 return BADFD
42}
43
44func (f *UnionFile) Read(s []byte) (int, error) {
45 if f.Layer != nil {
46 n, err := f.Layer.Read(s)
47 if (err == nil || err == io.EOF) && f.Base != nil {
48 // advance the file position also in the base file, the next
49 // call may be a write at this position (or a seek with SEEK_CUR)
50 if _, seekErr := f.Base.Seek(int64(n), os.SEEK_CUR); seekErr != nil {
51 // only overwrite err in case the seek fails: we need to
52 // report an eventual io.EOF to the caller
53 err = seekErr
54 }
55 }
56 return n, err
57 }
58 if f.Base != nil {
59 return f.Base.Read(s)
60 }
61 return 0, BADFD
62}
63
64func (f *UnionFile) ReadAt(s []byte, o int64) (int, error) {
65 if f.Layer != nil {
66 n, err := f.Layer.ReadAt(s, o)
67 if (err == nil || err == io.EOF) && f.Base != nil {
68 _, err = f.Base.Seek(o+int64(n), os.SEEK_SET)
69 }
70 return n, err
71 }
72 if f.Base != nil {
73 return f.Base.ReadAt(s, o)
74 }
75 return 0, BADFD
76}
77
78func (f *UnionFile) Seek(o int64, w int) (pos int64, err error) {
79 if f.Layer != nil {
80 pos, err = f.Layer.Seek(o, w)
81 if (err == nil || err == io.EOF) && f.Base != nil {
82 _, err = f.Base.Seek(o, w)
83 }
84 return pos, err
85 }
86 if f.Base != nil {
87 return f.Base.Seek(o, w)
88 }
89 return 0, BADFD
90}
91
92func (f *UnionFile) Write(s []byte) (n int, err error) {
93 if f.Layer != nil {
94 n, err = f.Layer.Write(s)
95 if err == nil && f.Base != nil { // hmm, do we have fixed size files where a write may hit the EOF mark?
96 _, err = f.Base.Write(s)
97 }
98 return n, err
99 }
100 if f.Base != nil {
101 return f.Base.Write(s)
102 }
103 return 0, BADFD
104}
105
106func (f *UnionFile) WriteAt(s []byte, o int64) (n int, err error) {
107 if f.Layer != nil {
108 n, err = f.Layer.WriteAt(s, o)
109 if err == nil && f.Base != nil {
110 _, err = f.Base.WriteAt(s, o)
111 }
112 return n, err
113 }
114 if f.Base != nil {
115 return f.Base.WriteAt(s, o)
116 }
117 return 0, BADFD
118}
119
120func (f *UnionFile) Name() string {
121 if f.Layer != nil {
122 return f.Layer.Name()
123 }
124 return f.Base.Name()
125}
126
127// DirsMerger is how UnionFile weaves two directories together.
128// It takes the FileInfo slices from the layer and the base and returns a
129// single view.
130type DirsMerger func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error)
131
132var defaultUnionMergeDirsFn = func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error) {
133 var files = make(map[string]os.FileInfo)
134
135 for _, fi := range lofi {
136 files[fi.Name()] = fi
137 }
138
139 for _, fi := range bofi {
140 if _, exists := files[fi.Name()]; !exists {
141 files[fi.Name()] = fi
142 }
143 }
144
145 rfi := make([]os.FileInfo, len(files))
146
147 i := 0
148 for _, fi := range files {
149 rfi[i] = fi
150 i++
151 }
152
153 return rfi, nil
154
155}
156
157// Readdir will weave the two directories together and
158// return a single view of the overlayed directories
159// At the end of the directory view, the error is io.EOF.
160func (f *UnionFile) Readdir(c int) (ofi []os.FileInfo, err error) {
161 var merge DirsMerger = f.Merger
162 if merge == nil {
163 merge = defaultUnionMergeDirsFn
164 }
165
166 if f.off == 0 {
167 var lfi []os.FileInfo
168 if f.Layer != nil {
169 lfi, err = f.Layer.Readdir(-1)
170 if err != nil {
171 return nil, err
172 }
173 }
174
175 var bfi []os.FileInfo
176 if f.Base != nil {
177 bfi, err = f.Base.Readdir(-1)
178 if err != nil {
179 return nil, err
180 }
181
182 }
183 merged, err := merge(lfi, bfi)
184 if err != nil {
185 return nil, err
186 }
187 f.files = append(f.files, merged...)
188 }
189
190 if f.off >= len(f.files) {
191 return nil, io.EOF
192 }
193
194 if c == -1 {
195 return f.files[f.off:], nil
196 }
197
198 if c > len(f.files) {
199 c = len(f.files)
200 }
201
202 defer func() { f.off += c }()
203 return f.files[f.off:c], nil
204}
205
206func (f *UnionFile) Readdirnames(c int) ([]string, error) {
207 rfi, err := f.Readdir(c)
208 if err != nil {
209 return nil, err
210 }
211 var names []string
212 for _, fi := range rfi {
213 names = append(names, fi.Name())
214 }
215 return names, nil
216}
217
218func (f *UnionFile) Stat() (os.FileInfo, error) {
219 if f.Layer != nil {
220 return f.Layer.Stat()
221 }
222 if f.Base != nil {
223 return f.Base.Stat()
224 }
225 return nil, BADFD
226}
227
228func (f *UnionFile) Sync() (err error) {
229 if f.Layer != nil {
230 err = f.Layer.Sync()
231 if err == nil && f.Base != nil {
232 err = f.Base.Sync()
233 }
234 return err
235 }
236 if f.Base != nil {
237 return f.Base.Sync()
238 }
239 return BADFD
240}
241
242func (f *UnionFile) Truncate(s int64) (err error) {
243 if f.Layer != nil {
244 err = f.Layer.Truncate(s)
245 if err == nil && f.Base != nil {
246 err = f.Base.Truncate(s)
247 }
248 return err
249 }
250 if f.Base != nil {
251 return f.Base.Truncate(s)
252 }
253 return BADFD
254}
255
256func (f *UnionFile) WriteString(s string) (n int, err error) {
257 if f.Layer != nil {
258 n, err = f.Layer.WriteString(s)
259 if err == nil && f.Base != nil {
260 _, err = f.Base.WriteString(s)
261 }
262 return n, err
263 }
264 if f.Base != nil {
265 return f.Base.WriteString(s)
266 }
267 return 0, BADFD
268}
269
270func copyToLayer(base Fs, layer Fs, name string) error {
271 bfh, err := base.Open(name)
272 if err != nil {
273 return err
274 }
275 defer bfh.Close()
276
277 // First make sure the directory exists
278 exists, err := Exists(layer, filepath.Dir(name))
279 if err != nil {
280 return err
281 }
282 if !exists {
283 err = layer.MkdirAll(filepath.Dir(name), 0777) // FIXME?
284 if err != nil {
285 return err
286 }
287 }
288
289 // Create the file on the overlay
290 lfh, err := layer.Create(name)
291 if err != nil {
292 return err
293 }
294 n, err := io.Copy(lfh, bfh)
295 if err != nil {
296 // If anything fails, clean up the file
297 layer.Remove(name)
298 lfh.Close()
299 return err
300 }
301
302 bfi, err := bfh.Stat()
303 if err != nil || bfi.Size() != n {
304 layer.Remove(name)
305 lfh.Close()
306 return syscall.EIO
307 }
308
309 err = lfh.Close()
310 if err != nil {
311 layer.Remove(name)
312 lfh.Close()
313 return err
314 }
315 return layer.Chtimes(name, bfi.ModTime(), bfi.ModTime())
316}
diff --git a/vendor/github.com/spf13/afero/util.go b/vendor/github.com/spf13/afero/util.go
new file mode 100644
index 0000000..4f253f4
--- /dev/null
+++ b/vendor/github.com/spf13/afero/util.go
@@ -0,0 +1,330 @@
1// Copyright ©2015 Steve Francia <spf@spf13.com>
2// Portions Copyright ©2015 The Hugo Authors
3// Portions Copyright 2016-present Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17package afero
18
19import (
20 "bytes"
21 "fmt"
22 "io"
23 "os"
24 "path/filepath"
25 "strings"
26 "unicode"
27
28 "golang.org/x/text/transform"
29 "golang.org/x/text/unicode/norm"
30)
31
32// Filepath separator defined by os.Separator.
33const FilePathSeparator = string(filepath.Separator)
34
35// Takes a reader and a path and writes the content
36func (a Afero) WriteReader(path string, r io.Reader) (err error) {
37 return WriteReader(a.Fs, path, r)
38}
39
40func WriteReader(fs Fs, path string, r io.Reader) (err error) {
41 dir, _ := filepath.Split(path)
42 ospath := filepath.FromSlash(dir)
43
44 if ospath != "" {
45 err = fs.MkdirAll(ospath, 0777) // rwx, rw, r
46 if err != nil {
47 if err != os.ErrExist {
48 return err
49 }
50 }
51 }
52
53 file, err := fs.Create(path)
54 if err != nil {
55 return
56 }
57 defer file.Close()
58
59 _, err = io.Copy(file, r)
60 return
61}
62
63// Same as WriteReader but checks to see if file/directory already exists.
64func (a Afero) SafeWriteReader(path string, r io.Reader) (err error) {
65 return SafeWriteReader(a.Fs, path, r)
66}
67
68func SafeWriteReader(fs Fs, path string, r io.Reader) (err error) {
69 dir, _ := filepath.Split(path)
70 ospath := filepath.FromSlash(dir)
71
72 if ospath != "" {
73 err = fs.MkdirAll(ospath, 0777) // rwx, rw, r
74 if err != nil {
75 return
76 }
77 }
78
79 exists, err := Exists(fs, path)
80 if err != nil {
81 return
82 }
83 if exists {
84 return fmt.Errorf("%v already exists", path)
85 }
86
87 file, err := fs.Create(path)
88 if err != nil {
89 return
90 }
91 defer file.Close()
92
93 _, err = io.Copy(file, r)
94 return
95}
96
97func (a Afero) GetTempDir(subPath string) string {
98 return GetTempDir(a.Fs, subPath)
99}
100
101// GetTempDir returns the default temp directory with trailing slash
102// if subPath is not empty then it will be created recursively with mode 777 rwx rwx rwx
103func GetTempDir(fs Fs, subPath string) string {
104 addSlash := func(p string) string {
105 if FilePathSeparator != p[len(p)-1:] {
106 p = p + FilePathSeparator
107 }
108 return p
109 }
110 dir := addSlash(os.TempDir())
111
112 if subPath != "" {
113 // preserve windows backslash :-(
114 if FilePathSeparator == "\\" {
115 subPath = strings.Replace(subPath, "\\", "____", -1)
116 }
117 dir = dir + UnicodeSanitize((subPath))
118 if FilePathSeparator == "\\" {
119 dir = strings.Replace(dir, "____", "\\", -1)
120 }
121
122 if exists, _ := Exists(fs, dir); exists {
123 return addSlash(dir)
124 }
125
126 err := fs.MkdirAll(dir, 0777)
127 if err != nil {
128 panic(err)
129 }
130 dir = addSlash(dir)
131 }
132 return dir
133}
134
135// Rewrite string to remove non-standard path characters
136func UnicodeSanitize(s string) string {
137 source := []rune(s)
138 target := make([]rune, 0, len(source))
139
140 for _, r := range source {
141 if unicode.IsLetter(r) ||
142 unicode.IsDigit(r) ||
143 unicode.IsMark(r) ||
144 r == '.' ||
145 r == '/' ||
146 r == '\\' ||
147 r == '_' ||
148 r == '-' ||
149 r == '%' ||
150 r == ' ' ||
151 r == '#' {
152 target = append(target, r)
153 }
154 }
155
156 return string(target)
157}
158
159// Transform characters with accents into plain forms.
160func NeuterAccents(s string) string {
161 t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
162 result, _, _ := transform.String(t, string(s))
163
164 return result
165}
166
167func isMn(r rune) bool {
168 return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks
169}
170
171func (a Afero) FileContainsBytes(filename string, subslice []byte) (bool, error) {
172 return FileContainsBytes(a.Fs, filename, subslice)
173}
174
175// Check if a file contains a specified byte slice.
176func FileContainsBytes(fs Fs, filename string, subslice []byte) (bool, error) {
177 f, err := fs.Open(filename)
178 if err != nil {
179 return false, err
180 }
181 defer f.Close()
182
183 return readerContainsAny(f, subslice), nil
184}
185
186func (a Afero) FileContainsAnyBytes(filename string, subslices [][]byte) (bool, error) {
187 return FileContainsAnyBytes(a.Fs, filename, subslices)
188}
189
190// Check if a file contains any of the specified byte slices.
191func FileContainsAnyBytes(fs Fs, filename string, subslices [][]byte) (bool, error) {
192 f, err := fs.Open(filename)
193 if err != nil {
194 return false, err
195 }
196 defer f.Close()
197
198 return readerContainsAny(f, subslices...), nil
199}
200
201// readerContains reports whether any of the subslices is within r.
202func readerContainsAny(r io.Reader, subslices ...[]byte) bool {
203
204 if r == nil || len(subslices) == 0 {
205 return false
206 }
207
208 largestSlice := 0
209
210 for _, sl := range subslices {
211 if len(sl) > largestSlice {
212 largestSlice = len(sl)
213 }
214 }
215
216 if largestSlice == 0 {
217 return false
218 }
219
220 bufflen := largestSlice * 4
221 halflen := bufflen / 2
222 buff := make([]byte, bufflen)
223 var err error
224 var n, i int
225
226 for {
227 i++
228 if i == 1 {
229 n, err = io.ReadAtLeast(r, buff[:halflen], halflen)
230 } else {
231 if i != 2 {
232 // shift left to catch overlapping matches
233 copy(buff[:], buff[halflen:])
234 }
235 n, err = io.ReadAtLeast(r, buff[halflen:], halflen)
236 }
237
238 if n > 0 {
239 for _, sl := range subslices {
240 if bytes.Contains(buff, sl) {
241 return true
242 }
243 }
244 }
245
246 if err != nil {
247 break
248 }
249 }
250 return false
251}
252
253func (a Afero) DirExists(path string) (bool, error) {
254 return DirExists(a.Fs, path)
255}
256
257// DirExists checks if a path exists and is a directory.
258func DirExists(fs Fs, path string) (bool, error) {
259 fi, err := fs.Stat(path)
260 if err == nil && fi.IsDir() {
261 return true, nil
262 }
263 if os.IsNotExist(err) {
264 return false, nil
265 }
266 return false, err
267}
268
269func (a Afero) IsDir(path string) (bool, error) {
270 return IsDir(a.Fs, path)
271}
272
273// IsDir checks if a given path is a directory.
274func IsDir(fs Fs, path string) (bool, error) {
275 fi, err := fs.Stat(path)
276 if err != nil {
277 return false, err
278 }
279 return fi.IsDir(), nil
280}
281
282func (a Afero) IsEmpty(path string) (bool, error) {
283 return IsEmpty(a.Fs, path)
284}
285
286// IsEmpty checks if a given file or directory is empty.
287func IsEmpty(fs Fs, path string) (bool, error) {
288 if b, _ := Exists(fs, path); !b {
289 return false, fmt.Errorf("%q path does not exist", path)
290 }
291 fi, err := fs.Stat(path)
292 if err != nil {
293 return false, err
294 }
295 if fi.IsDir() {
296 f, err := fs.Open(path)
297 if err != nil {
298 return false, err
299 }
300 defer f.Close()
301 list, err := f.Readdir(-1)
302 return len(list) == 0, nil
303 }
304 return fi.Size() == 0, nil
305}
306
307func (a Afero) Exists(path string) (bool, error) {
308 return Exists(a.Fs, path)
309}
310
311// Check if a file or directory exists.
312func Exists(fs Fs, path string) (bool, error) {
313 _, err := fs.Stat(path)
314 if err == nil {
315 return true, nil
316 }
317 if os.IsNotExist(err) {
318 return false, nil
319 }
320 return false, err
321}
322
323func FullBaseFsPath(basePathFs *BasePathFs, relativePath string) string {
324 combinedPath := filepath.Join(basePathFs.path, relativePath)
325 if parent, ok := basePathFs.source.(*BasePathFs); ok {
326 return FullBaseFsPath(parent, combinedPath)
327 }
328
329 return combinedPath
330}