├── src
├── Assets
│ └── Icons
│ │ └── icon.ico
├── Flaco.fsproj
├── Program.fs
└── Main.fs
├── .config
└── dotnet-tools.json
├── flaco.sln
├── README.md
└── .gitignore
/src/Assets/Icons/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AngelMunoz/package-fsharp-to-flatpak/HEAD/src/Assets/Icons/icon.ico
--------------------------------------------------------------------------------
/.config/dotnet-tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "isRoot": true,
4 | "tools": {
5 | "fantomas": {
6 | "version": "6.1.1",
7 | "commands": [
8 | "fantomas"
9 | ]
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/Flaco.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net7.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/flaco.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.0.31903.59
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Flaco", "src\Flaco.fsproj", "{CFDC2BA9-F171-4E9F-8BE0-83EEF678415A}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(SolutionProperties) = preSolution
14 | HideSolutionNode = FALSE
15 | EndGlobalSection
16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
17 | {CFDC2BA9-F171-4E9F-8BE0-83EEF678415A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
18 | {CFDC2BA9-F171-4E9F-8BE0-83EEF678415A}.Debug|Any CPU.Build.0 = Debug|Any CPU
19 | {CFDC2BA9-F171-4E9F-8BE0-83EEF678415A}.Release|Any CPU.ActiveCfg = Release|Any CPU
20 | {CFDC2BA9-F171-4E9F-8BE0-83EEF678415A}.Release|Any CPU.Build.0 = Release|Any CPU
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/src/Program.fs:
--------------------------------------------------------------------------------
1 | namespace Examples.CounterApp
2 |
3 | open System
4 |
5 | open Avalonia
6 | open Avalonia.Controls
7 | open Avalonia.Controls.ApplicationLifetimes
8 | open Avalonia.Themes.Fluent
9 | open Avalonia.FuncUI.Hosts
10 |
11 | type MainWindow() =
12 | inherit HostWindow()
13 |
14 | do
15 | base.Title <- "Counter Example"
16 | base.Height <- 400.0
17 | base.Width <- 400.0
18 | base.Content <- Main.view
19 |
20 | type App() =
21 | inherit Application()
22 |
23 | override this.Initialize() =
24 | this.Styles.Add(FluentTheme())
25 | this.RequestedThemeVariant <- Styling.ThemeVariant.Dark
26 |
27 | override this.OnFrameworkInitializationCompleted() =
28 | match this.ApplicationLifetime with
29 | | :? IClassicDesktopStyleApplicationLifetime as desktopLifetime ->
30 | let mainWindow = MainWindow()
31 | desktopLifetime.MainWindow <- mainWindow
32 | | _ -> ()
33 |
34 | module Program =
35 |
36 | []
37 | let main (args: string[]) =
38 | AppBuilder
39 | .Configure()
40 | .UsePlatformDetect()
41 | .UseSkia()
42 | .StartWithClassicDesktopLifetime(args)
43 |
--------------------------------------------------------------------------------
/src/Main.fs:
--------------------------------------------------------------------------------
1 | namespace Examples.CounterApp
2 |
3 | module Main =
4 | open Avalonia.Controls
5 | open Avalonia.FuncUI
6 | open Avalonia.FuncUI.DSL
7 | open Avalonia.Layout
8 |
9 | let view =
10 | Component (fun ctx ->
11 | let state = ctx.useState 0
12 |
13 | DockPanel.create [
14 | DockPanel.children [
15 | Button.create [
16 | Button.dock Dock.Bottom
17 | Button.onClick (fun _ -> state.Current - 1 |> state.Set)
18 | Button.content "-"
19 | Button.horizontalAlignment HorizontalAlignment.Stretch
20 | ]
21 | Button.create [
22 | Button.dock Dock.Bottom
23 | Button.onClick (fun _ -> state.Current + 1 |> state.Set)
24 | Button.content "+"
25 | Button.horizontalAlignment HorizontalAlignment.Stretch
26 | ]
27 | TextBlock.create [
28 | TextBlock.dock Dock.Top
29 | TextBlock.fontSize 48.0
30 | TextBlock.verticalAlignment VerticalAlignment.Center
31 | TextBlock.horizontalAlignment HorizontalAlignment.Center
32 | TextBlock.text (string state.Current)
33 | ]
34 | ]
35 | ]
36 | )
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Package an F# Avalonia app as a Flatpak
2 |
3 | > ### Flatpaks are not your thing?
4 | >
5 | > Try the packaging F# apps as a [snap](https://github.com/AngelMunoz/package-fsharp-to-snap/tree/main) then!
6 |
7 | > **_Note_**: While this example is written for F#, it should work for any .NET app.
8 |
9 | You're done with your app. Providing binaries is the next step, but you want to make it easy for your users to install and run your app. You also want to make it easy for you to distribute your app and even maybe auto-updates. You've heard about Flatpaks and want to try it out.
10 |
11 | This project is based on this _https://docs.flatpak.org/en/latest/first-build.html_ tutorial which has better information in regards of the flatpak build infrastructure.
12 |
13 | > **_Note_**:For this you should have set already the `org.flatpak.Builder`, `org.freedesktop.Platform`, and `org.freedesktop.Sdk` flatpaks. If you haven't, you can do so by following the instructions here: _https://docs.flatpak.org/en/latest/first-build.html#installing-the-flatpak-sdk_.
14 |
15 | ---
16 |
17 | Before we get into the juicy parts of the flatpak stuff. Let's build the app first.
18 |
19 | ```
20 | dotnet publish ./src -c Release -o ./flatpak/Flaco --self-contained -r linux-x64.
21 | ```
22 |
23 | in this case we'll use a self-contained app so we don't have to depend on the flatpak dotnet sdk or runtime.
24 |
25 | Ideally we just want to call a simple command and get running, nothing else.
26 |
27 | ## The Flatpak parts
28 |
29 | We will need a `flatpak` directory mainly for convenience and also to be sure we have what we need to build the flatpak.
30 |
31 | The manifest is relatively simple
32 |
33 | ```yaml
34 | # your app's id which ideally should match the manifest file name
35 | app-id: org.flatpak.Flaco
36 | runtime: org.freedesktop.Platform
37 | runtime-version: "22.08" # version of the runtime
38 | sdk: org.freedesktop.Sdk # the sdk to use
39 | command: Flaco # the command to run, basically the command that starts the app
40 | finish-args:
41 | # Flatpaks run in sandbox mode. This is the list of permissions we need
42 | # As we're running an Avalonia App, we need to specify that we want access
43 | # to the window infrastructure of the host
44 | - --socket=fallback-x11
45 | # for more information visit https://docs.flatpak.org/en/latest/sandbox-permissions.html#sandbox-permissions
46 |
47 | modules:
48 | # This is our app and the ;build' instructions for it
49 | - name: Flaco
50 | buildsystem: simple
51 | # In our case we've already run `dotnet publish` so we just need to copy the
52 | # outputs to the right place
53 | build-commands:
54 | - mkdir -p /app/bin
55 | - mv ./app-sources /app/bin/app-sources
56 | # allow our app to be executed
57 | - chmod +x /app/bin/app-sources/Flaco
58 | # create a symlink to the executable
59 | - ln -s /app/bin/app-sources/Flaco /app/bin/Flaco
60 | # This is the list of files/directories we want to copy to the flatpak
61 | # for more elaborated builds we could fetch a zip file, git repository or
62 | # even build from source however that comes with different challenges
63 | # so we'll leave that for another time
64 | sources:
65 | - type: dir
66 | # This is the path on the host machine './flatpak/Flaco'
67 | # but since we're running the flatpak-builder command in the flatpak directory
68 | # we'll omit the other one
69 | path: Flaco
70 | # This is the path inside the flatpak which gets copied to the root of the flatpak
71 | dest: app-sources
72 | ```
73 |
74 | Once we've built our dotnet app and have the manifest ready, we can build the flatpak.
75 |
76 | - `flatpak-builder --user --install --force-clean build-dir org.flatpak.Flaco.yml`
77 | - `--user`: we want to install the flatpak for the current user
78 | - `--install`: we want to install the flatpak after building it
79 | - `--force-clean`: we want to clean the build directory before building the flatpak
80 | - `flatpak run org.flatpak.Flaco`
81 |
82 | And that's it. The app should show on the screen and now we have a flatpak for our app tested and ready to be published in flathub!
83 |
84 | ### Extra Notes
85 |
86 | Thanks to [@scitesy](https://social.librem.one/@scitesy/110662886460321742) for providing me great resources to explore this area as well as the flatpak documentation.
87 | Also As noted by [@nlogozzo](https://mastodon.social/@nlogozzo/110662954309000176) (so much thanks, this helped me quite a lot!) when you run `flatpak-builder` you're not allowed to access the network anymore, so if you want to build from source your dotnet code you need to make a couple of extra workaround mainly involving the `sources` section of the manifest. So the dotnet sdk and NuGet have something to work with.
88 |
89 | As you may guess, the way we're building this right now makes apps quite heavy as we're not doing any trimming, or using any of the flatpak features to make the app lighter. But this is a good starting point.
90 |
91 | The following point could be to build the app as a runtime dependant app which can in turn use the dotnet runtime provided by the flatpak sdk. This would make the app lighter and also would allow us to use the flatpak to be more streamlined into it.
92 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # Tye
66 | .tye/
67 |
68 | # ASP.NET Scaffolding
69 | ScaffoldingReadMe.txt
70 |
71 | # StyleCop
72 | StyleCopReport.xml
73 |
74 | # Files built by Visual Studio
75 | *_i.c
76 | *_p.c
77 | *_h.h
78 | *.ilk
79 | *.meta
80 | *.obj
81 | *.iobj
82 | *.pch
83 | *.pdb
84 | *.ipdb
85 | *.pgc
86 | *.pgd
87 | *.rsp
88 | *.sbr
89 | *.tlb
90 | *.tli
91 | *.tlh
92 | *.tmp
93 | *.tmp_proj
94 | *_wpftmp.csproj
95 | *.log
96 | *.tlog
97 | *.vspscc
98 | *.vssscc
99 | .builds
100 | *.pidb
101 | *.svclog
102 | *.scc
103 |
104 | # Chutzpah Test files
105 | _Chutzpah*
106 |
107 | # Visual C++ cache files
108 | ipch/
109 | *.aps
110 | *.ncb
111 | *.opendb
112 | *.opensdf
113 | *.sdf
114 | *.cachefile
115 | *.VC.db
116 | *.VC.VC.opendb
117 |
118 | # Visual Studio profiler
119 | *.psess
120 | *.vsp
121 | *.vspx
122 | *.sap
123 |
124 | # Visual Studio Trace Files
125 | *.e2e
126 |
127 | # TFS 2012 Local Workspace
128 | $tf/
129 |
130 | # Guidance Automation Toolkit
131 | *.gpState
132 |
133 | # ReSharper is a .NET coding add-in
134 | _ReSharper*/
135 | *.[Rr]e[Ss]harper
136 | *.DotSettings.user
137 |
138 | # TeamCity is a build add-in
139 | _TeamCity*
140 |
141 | # DotCover is a Code Coverage Tool
142 | *.dotCover
143 |
144 | # AxoCover is a Code Coverage Tool
145 | .axoCover/*
146 | !.axoCover/settings.json
147 |
148 | # Coverlet is a free, cross platform Code Coverage Tool
149 | coverage*.json
150 | coverage*.xml
151 | coverage*.info
152 |
153 | # Visual Studio code coverage results
154 | *.coverage
155 | *.coveragexml
156 |
157 | # NCrunch
158 | _NCrunch_*
159 | .*crunch*.local.xml
160 | nCrunchTemp_*
161 |
162 | # MightyMoose
163 | *.mm.*
164 | AutoTest.Net/
165 |
166 | # Web workbench (sass)
167 | .sass-cache/
168 |
169 | # Installshield output folder
170 | [Ee]xpress/
171 |
172 | # DocProject is a documentation generator add-in
173 | DocProject/buildhelp/
174 | DocProject/Help/*.HxT
175 | DocProject/Help/*.HxC
176 | DocProject/Help/*.hhc
177 | DocProject/Help/*.hhk
178 | DocProject/Help/*.hhp
179 | DocProject/Help/Html2
180 | DocProject/Help/html
181 |
182 | # Click-Once directory
183 | publish/
184 |
185 | # Publish Web Output
186 | *.[Pp]ublish.xml
187 | *.azurePubxml
188 | # Note: Comment the next line if you want to checkin your web deploy settings,
189 | # but database connection strings (with potential passwords) will be unencrypted
190 | *.pubxml
191 | *.publishproj
192 |
193 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
194 | # checkin your Azure Web App publish settings, but sensitive information contained
195 | # in these scripts will be unencrypted
196 | PublishScripts/
197 |
198 | # NuGet Packages
199 | *.nupkg
200 | # NuGet Symbol Packages
201 | *.snupkg
202 | # The packages folder can be ignored because of Package Restore
203 | **/[Pp]ackages/*
204 | # except build/, which is used as an MSBuild target.
205 | !**/[Pp]ackages/build/
206 | # Uncomment if necessary however generally it will be regenerated when needed
207 | #!**/[Pp]ackages/repositories.config
208 | # NuGet v3's project.json files produces more ignorable files
209 | *.nuget.props
210 | *.nuget.targets
211 |
212 | # Microsoft Azure Build Output
213 | csx/
214 | *.build.csdef
215 |
216 | # Microsoft Azure Emulator
217 | ecf/
218 | rcf/
219 |
220 | # Windows Store app package directories and files
221 | AppPackages/
222 | BundleArtifacts/
223 | Package.StoreAssociation.xml
224 | _pkginfo.txt
225 | *.appx
226 | *.appxbundle
227 | *.appxupload
228 |
229 | # Visual Studio cache files
230 | # files ending in .cache can be ignored
231 | *.[Cc]ache
232 | # but keep track of directories ending in .cache
233 | !?*.[Cc]ache/
234 |
235 | # Others
236 | ClientBin/
237 | ~$*
238 | *~
239 | *.dbmdl
240 | *.dbproj.schemaview
241 | *.jfm
242 | *.pfx
243 | *.publishsettings
244 | orleans.codegen.cs
245 |
246 | # Including strong name files can present a security risk
247 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
248 | #*.snk
249 |
250 | # Since there are multiple workflows, uncomment next line to ignore bower_components
251 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
252 | #bower_components/
253 |
254 | # RIA/Silverlight projects
255 | Generated_Code/
256 |
257 | # Backup & report files from converting an old project file
258 | # to a newer Visual Studio version. Backup files are not needed,
259 | # because we have git ;-)
260 | _UpgradeReport_Files/
261 | Backup*/
262 | UpgradeLog*.XML
263 | UpgradeLog*.htm
264 | ServiceFabricBackup/
265 | *.rptproj.bak
266 |
267 | # SQL Server files
268 | *.mdf
269 | *.ldf
270 | *.ndf
271 |
272 | # Business Intelligence projects
273 | *.rdl.data
274 | *.bim.layout
275 | *.bim_*.settings
276 | *.rptproj.rsuser
277 | *- [Bb]ackup.rdl
278 | *- [Bb]ackup ([0-9]).rdl
279 | *- [Bb]ackup ([0-9][0-9]).rdl
280 |
281 | # Microsoft Fakes
282 | FakesAssemblies/
283 |
284 | # GhostDoc plugin setting file
285 | *.GhostDoc.xml
286 |
287 | # Node.js Tools for Visual Studio
288 | .ntvs_analysis.dat
289 | node_modules/
290 |
291 | # Visual Studio 6 build log
292 | *.plg
293 |
294 | # Visual Studio 6 workspace options file
295 | *.opt
296 |
297 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
298 | *.vbw
299 |
300 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
301 | *.vbp
302 |
303 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
304 | *.dsw
305 | *.dsp
306 |
307 | # Visual Studio 6 technical files
308 | *.ncb
309 | *.aps
310 |
311 | # Visual Studio LightSwitch build output
312 | **/*.HTMLClient/GeneratedArtifacts
313 | **/*.DesktopClient/GeneratedArtifacts
314 | **/*.DesktopClient/ModelManifest.xml
315 | **/*.Server/GeneratedArtifacts
316 | **/*.Server/ModelManifest.xml
317 | _Pvt_Extensions
318 |
319 | # Paket dependency manager
320 | .paket/paket.exe
321 | paket-files/
322 |
323 | # FAKE - F# Make
324 | .fake/
325 |
326 | # CodeRush personal settings
327 | .cr/personal
328 |
329 | # Python Tools for Visual Studio (PTVS)
330 | __pycache__/
331 | *.pyc
332 |
333 | # Cake - Uncomment if you are using it
334 | # tools/**
335 | # !tools/packages.config
336 |
337 | # Tabs Studio
338 | *.tss
339 |
340 | # Telerik's JustMock configuration file
341 | *.jmconfig
342 |
343 | # BizTalk build output
344 | *.btp.cs
345 | *.btm.cs
346 | *.odx.cs
347 | *.xsd.cs
348 |
349 | # OpenCover UI analysis results
350 | OpenCover/
351 |
352 | # Azure Stream Analytics local run output
353 | ASALocalRun/
354 |
355 | # MSBuild Binary and Structured Log
356 | *.binlog
357 |
358 | # NVidia Nsight GPU debugger configuration file
359 | *.nvuser
360 |
361 | # MFractors (Xamarin productivity tool) working folder
362 | .mfractor/
363 |
364 | # Local History for Visual Studio
365 | .localhistory/
366 |
367 | # Visual Studio History (VSHistory) files
368 | .vshistory/
369 |
370 | # BeatPulse healthcheck temp database
371 | healthchecksdb
372 |
373 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
374 | MigrationBackup/
375 |
376 | # Ionide (cross platform F# VS Code tools) working folder
377 | .ionide/
378 |
379 | # Fody - auto-generated XML schema
380 | FodyWeavers.xsd
381 |
382 | # VS Code files for those working on multiple tools
383 | .vscode/*
384 | !.vscode/settings.json
385 | !.vscode/tasks.json
386 | !.vscode/launch.json
387 | !.vscode/extensions.json
388 | *.code-workspace
389 |
390 | # Local History for Visual Studio Code
391 | .history/
392 |
393 | # Windows Installer files from build outputs
394 | *.cab
395 | *.msi
396 | *.msix
397 | *.msm
398 | *.msp
399 |
400 | # JetBrains Rider
401 | *.sln.iml
402 |
403 | ##
404 | ## Visual studio for Mac
405 | ##
406 |
407 |
408 | # globs
409 | Makefile.in
410 | *.userprefs
411 | *.usertasks
412 | config.make
413 | config.status
414 | aclocal.m4
415 | install-sh
416 | autom4te.cache/
417 | *.tar.gz
418 | tarballs/
419 | test-results/
420 |
421 | # Mac bundle stuff
422 | *.dmg
423 | *.app
424 |
425 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
426 | # General
427 | .DS_Store
428 | .AppleDouble
429 | .LSOverride
430 |
431 | # Icon must end with two \r
432 | Icon
433 |
434 |
435 | # Thumbnails
436 | ._*
437 |
438 | # Files that might appear in the root of a volume
439 | .DocumentRevisions-V100
440 | .fseventsd
441 | .Spotlight-V100
442 | .TemporaryItems
443 | .Trashes
444 | .VolumeIcon.icns
445 | .com.apple.timemachine.donotpresent
446 |
447 | # Directories potentially created on remote AFP share
448 | .AppleDB
449 | .AppleDesktop
450 | Network Trash Folder
451 | Temporary Items
452 | .apdisk
453 |
454 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
455 | # Windows thumbnail cache files
456 | Thumbs.db
457 | ehthumbs.db
458 | ehthumbs_vista.db
459 |
460 | # Dump file
461 | *.stackdump
462 |
463 | # Folder config file
464 | [Dd]esktop.ini
465 |
466 | # Recycle Bin used on file shares
467 | $RECYCLE.BIN/
468 |
469 | # Windows Installer files
470 | *.cab
471 | *.msi
472 | *.msix
473 | *.msm
474 | *.msp
475 |
476 | # Windows shortcuts
477 | *.lnk
478 |
479 | flatpak/
480 | !flatpak/org.flatpak.Flaco.yml
--------------------------------------------------------------------------------