Need help converting Flatpak YAML to Snap YAML. How to apply patch to source code before creating snap?

So, I have successfully built a Flatpak for a simple CLI application which requires a small patch to the source code because otherwise it won’t compile.

For the Flatpak, I have saved the .yml file and the .patch file in the same directory, and then the Flatpak .yml file contains the following code:

modules:

(the bullet points above should hyphens, not sure how to keep the source formatting)

I’m not quite sure how to translate this section into a Snap YAML because I think this app would actually work much better as a Snap than as a Flatpak as it doesn’t have a GUI. Any help is much appreciated!

A real world example for you

The patches are in $CRAFT_PROJECT_DIR/snap/local because it has better results with the Launchpad build service, but they don’t have to be there.

1 Like

Thanks! To be honest, it’s a bit complicated for me to understand (I don’t have a tech background or programming experience). I created a “.patch” file using “diff”. The difference is just one single character in a “.cpp” file that needs to be added because otherwise it won’t compile.

How would I do this? Is there something like “override-build: apply mypatch.patch”? Or “override-build: mv patched.cpp original.cpp”?

override-pull, and the other equivilents (e.g override-build) are all Bash scripts. In the example above, we have:

override-pull: | 
  craftctl default  

craftl default, or in older versions (before Core22), snapcraftctl pull, means do the default beaviour. In the context of a pull, that would be download from Git, HTTPS, copy a local folder, etc.

We can ignore the set version because it’s not super relevant.

The for loop is for applying multiple patches, if you’ve only one, you could skip the for loop and do e.g

patch -i path_to_patch_file.patch

e.g:

override-pull: |
  craftctl default
  patch -i my_patch.patch

If it made more sense for you to do mv file.a file.b, that would work too. You could write anything that Bash would accept in the override.

But in theory, the combination of diff (or usually diff -Naur) and patch to apply a diff are the standard tools for the job. mv could work, but if you’ve already a patch file that otherwise works well, it’s probably easier to stick with the right tool for the job :slight_smile:

2 Likes

Great, thank you for the quick reply! That makes a lot of sense, I will try it. :slight_smile:

I tried this now but I’m getting an error code 2. It says it can’t find the patch file.

edit: it works when I use your for-loop from the Joplin YAML!

Although I do get a compile error now instead:

Executed: pull gnuclad                                                         
Executed: overlay gnuclad                                                      
Executed: build gnuclad                                                        
Executed: stage gnuclad                                                        
Executed: prime gnuclad                                                        
Executed parts lifecycle                                                       
Generated snap metadata                                                        
Cannot pack snap file: Command '['snap', 'pack', '--filename', 'gnuclad_0.2.4_amd64.snap', '--compression', 'xz', PosixPath('/root/prime'), PosixPath('/root/project')]' returned non-zero exit status 1. (2023/03/03 10:47:58.608196 container.go:215: in snap "gnuclad": path "gnuclad" does not exist
error: cannot pack "/root/prime": snap is unusable due to missing files)                              
Failed to execute pack in instance.      

Hey,

Refering to the original revision of your post before you used the for-loop, the problem will have been specifying snap/local as the path. The current working directory changes for each build stage, so you’ll have been implicitly trying to find $CRAFT_PART_SRC/snap rather than $CRAFT_PROJECT_DIR/snap, which is why the for-loop works but the singular line didn’t.

Regarding the packing error, try running snapcraft with: snapcraft --debug

This will drop you into the VM/LXD shell the snap is built in and allow you to inspect the filesystem. For LXD, stuff is usually kept in /root/parts, e.g, /root/parts/gnuclad/src or /root/parts/gnuclad/build etc; but in your snapcraft.yaml you should always refer to these with the environment variables because they can move around across bases and implementations!

In any case, in the shell that’ll open from snapcraft --debug, try doing

ls /root/prime

Is there anything in it? There should be everything your app has built and all the stages packages. If your command is e.g bin/gnuclad, then there should be /root/prime/bin/gnuclad, if not, you’ll need to either change the command to point to where the binary is (relative to the $SNAP variable at runtime, so don’t put /root/prime!), or determine why the binary doesn’t exist.

If you can’t find the binary in /root/prime, try:

ls /root/parts/gnuclad/install

Is there anything in there? If not, try

ls /root/parts/gnuclad/build

Is there anything in there? (Hopefully!).

Ideally the build artefacts/binaries end up in install, which then propogates to the final /root/prime. However in some cases you might find certain build environments will place the final artefacts in build and not install, so they don’t propogate through to the final result.

Unfortunately I’m writing these paths based on memory so they might be slightly incorrect, but in summary:

  1. Check if the command value points to the right binary
  2. Check the binary exists in prime
  3. If it doesn’t, check if it exists in the install folder
  4. If it doesn’t, check if it exists in the build folder

But ultimately I reckon your command is command: gnuclad and probably needs to be command: bin/gnuclad or command: usr/bin/gnuclad :slight_smile:

1 Like

That was why! I found the file in /root/prime/usr/local/bin/gnuclad. To fix it, I went to the YAML file and changed command: gnuclad to command: usr/local/bin/gnuclad and it built successfully now. Thank you so much again!