Dawn's Blogs

分享技术 记录成长

0%

阅读dubbo-kubernetes的启发 (1) 抽象文件系统

文件系统抽象

在 dubbo-kubernetes 中,利用 golang 提供的 fs 抽象接口,实现了多种不同文件系统。各种文件系统的实现在 app/dubboctl/internal/filesystem 文件夹下,首先定义了一个 Filesystem 接口:

1
2
3
4
5
type Filesystem interface {
fs.ReadDirFS
fs.StatFS
Readlink(link string) (string, error)
}

Filesystem 接口将访问 template 文件(至于什么是模版,可以不知道)的各种实现差异,封装到这个接口中。Filesystem 接口的实现包括以下:

  • zipFS:用于对 zip 压缩文件的读写,将 zip 压缩文件作为一个文件系统,压缩文件中的一个个被压缩的文件或者文件夹就是文件系统中的文件。
  • billyFS:表示 git repo 中的文件系统,用于访问在远程 git 仓库中的 template。
  • osFilesystem:由操作系统支持的文件系统,用于访问 template。
  • subFS:表示 Filesystem 中的子目录,单独作为一个文件系统。
  • maskingFS:基于 Filesystem,用于屏蔽某些文件的文件系统。

Golang 提供了 io.Reader 和 io.Writer 接口,抽象出对文件、字节流、socket 的读写。至于问什么提出这样的接口,将对象看作是文件一样读写,可以在 Linux 中找到启发:Linux 中,一切皆是文件

在 1.6 中提供了 fs.FS 抽象文件系统抽象,既然很多对象可以被看作是对象,那么这些抽象的文件聚集起来,就可以抽象出文件系统。

实现细节

zipFS

zipFS 结构体内部定义了一个 zip.Reader 类型的 archive,而 zip.Reader 已经实现了 fs.FS 接口。

1
2
3
type zipFS struct {
archive *zip.Reader
}

billyFilesystem

基于 go-git/go-bill 文件系统,用于访问远程 git 仓库,将远程 git 仓库作为一个文件系统抽象出来。

Github地址:https://github.com/go-git/go-billy

1
2
// BillyFilesystem is a template file accessor backed by a billy FS
type BillyFilesystem struct{ fs billy.Filesystem }

osFilesystem

osFilesystem 的定义如下,以当前操作系统中的 root 路径为 osFilesystem 的根目录

1
2
// osFilesystem is a template file accessor backed by the os.
type osFilesystem struct{ root string }

在 Open 方法中,使用 name 是以 root 为根目录相对路径:

1
2
3
4
func (o osFilesystem) Open(name string) (fs.File, error) {
name = filepath.FromSlash(name)
return os.Open(filepath.Join(o.root, name))
}

subFS

进一步的,subFS 表示 Filesystem 接口的子目录,并且以 Filesystem 的子目录为根目录。

1
2
3
4
5
// subFS exposes subdirectory of underlying FS, this is similar to `chroot`.
type subFS struct {
root string
fs Filesystem
}

Open 的实现如下:

1
2
3
func (o subFS) Open(name string) (fs.File, error) {
return o.fs.Open(path.Join(o.root, name))
}

maskingFS

maskingFS 表示 Filesystem 文件系统中,屏蔽某些文件的文件系统。其中,masked 函数用于根据文件名判断是否屏蔽。

1
2
3
4
type maskingFS struct {
masked func(path string) bool
fs Filesystem
}

Open 的实现如下,在打开文件之前,会首先调用 masked 方法判断文件是否被屏蔽:

1
2
3
4
5
6
func (m maskingFS) Open(name string) (fs.File, error) {
if m.masked(name) {
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
}
return m.fs.Open(name)
}