Probably silly question with file or paths deploying to Fly.io

Where is the server’s priv folder on Fly? I’m having trouble finding a file that I hope is being copied correctly during deployment.

For more context, for Metamorphic’s passphrase generator it uses the eff_large_wordlist.txt and subsequent strategy.

The GenServer for this is started in the Application:

...
# Start the word retrieval GenServer API for password generator.
{Metamorphic.Extensions.PasswordGenerator.WordRepository, %{}},
...

Then, there’s a WordLoader file that calls:

# I've also used Application.app_dir(@otp_app, "/priv/dict/eff_large_wordlist.txt") 
# with success locally.
@word_list_contents File.stream!(
  Path.join(:code.priv_dir(@otp_app), "/dict/eff_large_wordlist.txt")
)

This worked great in deployment with Render and locally. When deploying to Fly I run into the enoent error and that it was looking for the file at /app/_build/prod/lib/<@otp_app>/priv/dict/eff_large_wordlist.txt.

In the Docker file it runs the command COPY priv priv.

My local file structure root priv directory looks like /home/user/github/name/priv.

I’m not super familiar with Docker, but my understanding is that COPY priv priv is copying all the files in my priv folder over to a priv folder for the server on Fly. Is it copying the folder structure? I’ve used both Application.app_dir/2 and :code.priv_dir/1 and both work except for deployment to Fly (which my thinking is because I’m either not copying the file over and/or not finding it correctly).

Thanks for any help :blush:

So in my production deploy, it is in:

/app/lib/my_app-1.0/priv

The rest of libraries also have a priv directory.

I’m accessing that directory via:

app = Mix.Project.config[:app]
path = :filename.join(:code.priv_dir(unquote(app)), 'the_file')

It seems you’ve already tried these though, so I’m not sure exactly what you’re missing.

I’d suggest logging in via ssh and checking if the file exists on disk.

$ fly ssh console -a your_app
``
1 Like

Thank you! I should have ssh’d in and checked. That revealed that it was in the same location as yours.

/app/lib/my_app-version/priv/dict/eff_large_wordlist.txt

This works for me:

 otp_app = Mix.Project.config()[:app]
 version = Mix.Project.config()[:version]

  if Mix.env() in [:prod] do
    @word_list_contents File.stream!(
       "/app/lib/#{otp_app}-#{version}/priv/dict/eff_large_wordlist.txt"
    )
  else
    @word_list_contents File.stream!(
      Path.join(:code.priv_dir(otp_app), "/dict/eff_large_wordlist.txt")
    )
  end
1 Like

Hmmm…you know, I think the original code I posted was incorrect as that path is no longer used in my code. I think the following might work better and remove the if statement.

priv_dir = Application.app_dir(:the_app_name, "priv")

After logging in and /app/bin/the_app remote :

iex(the-app@fdaa:0:7ce1:a7b:a15f:dfdd:c76d:2)2> Application.app_dir(:the_app, "priv")
"/app/lib/the-app-1.0/priv"

Super-surprised that it didn’t work originally for you, seems like a bit of a weird footgun.

Yea, hm I wonder if it has something to do with it trying to build the release? Because it would always return the file path of /app/_build/... whenever using Application.app_dir/2 or :code.priv_dir/1.

The docker file is using mix release by default and it works for me, so I don’t think it’s that. Anyway, definitely an odd one.

1 Like

Make sure you run that code at runtime and not compile time.

2 Likes

Yea thanks! I did a quick test and deployed to Fly with this and it works:

@otp_app Mix.Project.config()[:app]

def load_words do
  File.stream!(Path.join(:code.priv_dir(@otp_app), "/dict/eff_large_wordlist.txt"))
  ...
end

Whereas before I was setting that as an attribute constant:

...
@word_list_contents File.stream!(Path.join(:code.priv_dir(@otp_app), "/dict/eff_large_wordlist.txt"))

def load_words do
  word_list_contents
  ...
end

So, as I’m understanding, when building for the Fly release it compiles the attribute @word_list_contents and then returning the wrong file path of /app/_build/.... I didn’t realize that because when deploying to Render I think it was compiled locally and then sent up (because I never ran into this issue on Render)?

1 Like