spf13 / afero

A FileSystem Abstraction System for Go
Apache License 2.0
5.8k stars 498 forks source link

Support for embed.FS? #337

Open crunk1 opened 2 years ago

crunk1 commented 2 years ago

Hey guys, new to afero and semi-new to embed.FS (used embed a bit, but unaware if embed is not-recommended or whatever).

I like the idea behind go:embed. In specific, I'm trying to bake config files into my binary. The config files are loaded via viper. I see viper has a SetFS function, only, it doesn't accept os.FS (which embed.FS implements).

Is there a reason embed.FS isn't supported?

malaclypse commented 2 years ago

I want to second this question as I've run into the same issue just now.

michaeltlombardi commented 2 years ago

I suspect that the reason for this has to do with the limited implementation of embed.FS - it only has Open(), ReadDir(), and ReadFile().

I believe it should be possible to make an implementation that borrows heavily from the ReadOnlyFS implementation as it has similar, though stricter, limitations.

bep commented 2 years ago

The config files are loaded via viper. I see viper has a SetFS function, only, it doesn't accept os.FS (which embed.FS implements).

I notice there are two-way-adapters for os.Fs, couldn't you do:

var emfs embed.FS
viper.SetFs(afero.FromIOFS{Fs: emfs })

?

Micaso commented 1 year ago

@bep your snipped gave the hint to get it working for me. But one have to adjust more to get it running. But this is more a problem of viper not afero.

To get it running for viper I have done following:

type MyFS struct {
    afero.FromIOFS
}

// Open will be overridden to strip the "/" away since viper will use an absolute path
func (receiver MyFS) Open(name string) (afero.File, error) {
    name = trimLeftChar(name)

    return receiver.FromIOFS.Open(name)
}

// Stat will be overridden to strip the "/" away since viper will use an absolute path
func (receiver MyFS) Stat(name string) (os.FileInfo, error) {
    name = trimLeftChar(name)

    return receiver.FromIOFS.Stat(name)
}
conf := viper.New()
conf.SetFs(MyFS{afero.FromIOFS{FS: embedFs}})

Hope that will help someone who struggle with it

crunk1 commented 1 year ago

@bep viper.SetFs(afero.FromIOFS{Fs: emfs}) works for reading a config into viper, thank you! Much cleaner than my own shim type I wrote :smiley:. I initially looked at ReadOnlyFs because embedded files/filesystems are read-only and I wanted to reiterate/enforce that.

I'm guessing that if you tried to use viper.SafeWriteConfigAs or otherwise tried to write to a FromIOFS-wrapped embed.Fs, you'd get an error.

bep commented 1 year ago

I'm guessing that if you tried to use viper.SafeWriteConfigAs or otherwise tried to write to a FromIOFS-wrapped embed.Fs, you'd get an error.

It's a long time since I looked at SafeWriteConfigAs, but the embed FS is readonly, so you will get an error on any write.