gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

filesystem.go (3781B)


      1 // Copyright 2019 The CC Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package cc
      6 
      7 import (
      8 	"io"
      9 	"io/ioutil"
     10 	"os"
     11 	"path"
     12 	"strings"
     13 	"time"
     14 )
     15 
     16 // Filesystem abstraction used in CC. The underlying value must be comparable (e.g. pointer) to be used in map keys.
     17 type Filesystem interface {
     18 	// Stat is an analog of os.Stat, but also accepts a flag to indicate a system include (<file.h>).
     19 	Stat(path string, sys bool) (os.FileInfo, error)
     20 	// Open is an analog of os.Open, but also accepts a flag to indicate a system include (<file.h>).
     21 	Open(path string, sys bool) (io.ReadCloser, error)
     22 }
     23 
     24 // LocalFS returns a local filesystem implementation.
     25 func LocalFS() Filesystem {
     26 	return localFS{}
     27 }
     28 
     29 type localFS struct{}
     30 
     31 // Stat implements Filesystem.
     32 func (localFS) Stat(path string, sys bool) (os.FileInfo, error) {
     33 	return os.Stat(path)
     34 }
     35 
     36 // Open implements Filesystem.
     37 func (localFS) Open(path string, sys bool) (io.ReadCloser, error) {
     38 	return os.Open(path)
     39 }
     40 
     41 // WorkingDir is a filesystem implementation that resolves paths relative to a given directory.
     42 // If filesystem is not specified, the local one will be used.
     43 func WorkingDir(wd string, fs Filesystem) Filesystem {
     44 	if fs == nil {
     45 		fs = LocalFS()
     46 	}
     47 	return workDir{fs: fs, wd: wd}
     48 }
     49 
     50 type workDir struct {
     51 	fs Filesystem
     52 	wd string
     53 }
     54 
     55 // Stat implements Filesystem.
     56 func (fs workDir) Stat(fname string, sys bool) (os.FileInfo, error) {
     57 	if !path.IsAbs(fname) {
     58 		fname = path.Join(fs.wd, fname)
     59 	}
     60 	return fs.fs.Stat(fname, sys)
     61 }
     62 
     63 // Open implements Filesystem.
     64 func (fs workDir) Open(fname string, sys bool) (io.ReadCloser, error) {
     65 	if !path.IsAbs(fname) {
     66 		fname = path.Join(fs.wd, fname)
     67 	}
     68 	return fs.fs.Open(fname, sys)
     69 }
     70 
     71 // Overlay is a filesystem implementation that first check if the file is available in the primary FS
     72 // and if not, falls back to a secondary FS.
     73 func Overlay(pri, sec Filesystem) Filesystem {
     74 	return overlayFS{pri: pri, sec: sec}
     75 }
     76 
     77 type overlayFS struct {
     78 	pri, sec Filesystem
     79 }
     80 
     81 // Stat implements Filesystem.
     82 func (fs overlayFS) Stat(path string, sys bool) (os.FileInfo, error) {
     83 	st, err := fs.pri.Stat(path, sys)
     84 	if err == nil || !os.IsNotExist(err) {
     85 		return st, err
     86 	}
     87 	return fs.sec.Stat(path, sys)
     88 }
     89 
     90 // Open implements Filesystem.
     91 func (fs overlayFS) Open(path string, sys bool) (io.ReadCloser, error) {
     92 	f, err := fs.pri.Open(path, sys)
     93 	if err == nil || !os.IsNotExist(err) {
     94 		return f, err
     95 	}
     96 	return fs.sec.Open(path, sys)
     97 }
     98 
     99 // StaticFS implements filesystem interface by serving string values form the provided map.
    100 func StaticFS(files map[string]string) Filesystem {
    101 	return &staticFS{m: files, ts: time.Now()}
    102 }
    103 
    104 type staticFS struct {
    105 	ts time.Time
    106 	m  map[string]string
    107 }
    108 
    109 // Stat implements Filesystem.
    110 func (fs *staticFS) Stat(path string, sys bool) (os.FileInfo, error) {
    111 	v, ok := fs.m[path]
    112 	if !ok {
    113 		return nil, &os.PathError{"stat", path, os.ErrNotExist}
    114 	}
    115 	return staticFileInfo{name: path, size: int64(len(v)), mode: 0, mod: fs.ts}, nil
    116 }
    117 
    118 // Open implements Filesystem.
    119 func (fs *staticFS) Open(path string, sys bool) (io.ReadCloser, error) {
    120 	v, ok := fs.m[path]
    121 	if !ok {
    122 		return nil, &os.PathError{"open", path, os.ErrNotExist}
    123 	}
    124 	return ioutil.NopCloser(strings.NewReader(v)), nil
    125 }
    126 
    127 type staticFileInfo struct {
    128 	name string
    129 	size int64
    130 	mode os.FileMode
    131 	mod  time.Time
    132 }
    133 
    134 func (fi staticFileInfo) Name() string {
    135 	return fi.name
    136 }
    137 
    138 func (fi staticFileInfo) Size() int64 {
    139 	return fi.size
    140 }
    141 
    142 func (fi staticFileInfo) Mode() os.FileMode {
    143 	return fi.mode
    144 }
    145 
    146 func (fi staticFileInfo) ModTime() time.Time {
    147 	return fi.mod
    148 }
    149 
    150 func (fi staticFileInfo) IsDir() bool {
    151 	return fi.mode.IsDir()
    152 }
    153 
    154 func (fi staticFileInfo) Sys() interface{} {
    155 	return fi
    156 }