yesodweb/yesod

static folder not found when Yesod app run from monorepo using cabal.project

Closed this issue · 4 comments

I'm on NixOS 23.05 and using Cabal to manage a monorepo (using cabal.project) with a Yesod app project (let's call it myyesod) inside it. I noticed that starting the app with cabal run myproject from the monorepo repository root folder fails with

monorepo$ cabal run myyesod
myyesod: static: getDirectoryContents:openDirStream: does not exist (No such file or directory)

while running it from the myyesod project (sub)folder works fine:

monorepo/myyesod$ cabal run myyesod
...
Preprocessing executable 'myyesod' for myyesod-0.0.0..
Building executable 'myyesod' for myyesod-0.0.0

I do not understand Yesod deep enough (yet) to create a fix myself, but i hope someone else might be able to. At least there's a workaround by just switching into the project folder for now.

Steps to reproduce: I got error when testing with the Yesod example project https://github.com/yesodweb/yesod-scaffold/tree/sqlite
inside a monorepo using stack new myyesod yesodweb/sqlite and adding that folder to cabal.project. I got the following Haskell package versions:

yesod 1.6.2.1
yesod-static 1.6.1.0
yesod-auth 1.6.11.1
yesod-core 1.6.24.4
yesod-form 1.7.4
yesod-newsfeed 1.7.0.0
yesod-persistent 1.6.0.8

The static dir is defined in config/settings.yml (at least in my project) as:

static-dir:     "_env:YESOD_STATIC_DIR:static"

So unless there is a env variable defined, Yesod uses the relative path static. That means you have to start your app from the correct directory. Or you export an env variable.

I see. This still feels inconsistent however, because other project-relative paths like config/settings.yaml (see definition)

-- | Raw bytes at compile time of @config/settings.yml@
configSettingsYmlBS :: ByteString
configSettingsYmlBS = $(embedFile configSettingsYml)

are found and loaded correctly from outside the project (i.e. from the monorepo root).

Are you sure that config/settings.yml is converted to an absolute path? I haven't looked up the definition of embedFile but it looks like the file is read and embedded at compile time; compilation is usually done from the project root.

Ah that makes sense. At compile time a relative project path can be resolved. At runtime the app can only know relative paths relative to the process working directory.