Skip to content

Commit 9e84688

Browse files
committed
feat: add support for Podman as an alternative runtime and persistant settings
- Implemented .yaml configuration system to manage persistant settings like runtime (Docker/Podman) and layout. - Implemented runtime selection in the TUI, allowing users to switch between Docker and Podman. - Updated container management functions to utilize the selected runtime for commands. - Enhanced the settings model to include runtime options and persist user preferences. - Added a restart mechanism to apply runtime changes without manual intervention. - Improved error handling and PreChecks for podman.
1 parent 6d3ec04 commit 9e84688

File tree

9 files changed

+1014
-307
lines changed

9 files changed

+1014
-307
lines changed

go.mod

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,31 @@ module github.com/shubh-io/dockmate
33
go 1.24.0
44

55
require (
6-
github.com/charmbracelet/bubbles v0.16.1
7-
github.com/charmbracelet/bubbletea v0.24.2
8-
github.com/charmbracelet/lipgloss v0.7.1
6+
github.com/charmbracelet/bubbles v0.21.0
7+
github.com/charmbracelet/bubbletea v1.3.4
8+
github.com/charmbracelet/lipgloss v1.1.0
9+
gopkg.in/yaml.v3 v3.0.1
910
)
1011

1112
require (
13+
github.com/atotto/clipboard v0.1.4 // indirect
1214
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
13-
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
15+
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
16+
github.com/charmbracelet/x/ansi v0.8.0 // indirect
17+
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
18+
github.com/charmbracelet/x/term v0.2.1 // indirect
19+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
1420
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
1521
github.com/mattn/go-isatty v0.0.20 // indirect
1622
github.com/mattn/go-localereader v0.0.1 // indirect
1723
github.com/mattn/go-runewidth v0.0.16 // indirect
1824
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
1925
github.com/muesli/cancelreader v0.2.2 // indirect
20-
github.com/muesli/reflow v0.3.0 // indirect
21-
github.com/muesli/termenv v0.15.2 // indirect
26+
github.com/muesli/termenv v0.16.0 // indirect
2227
github.com/rivo/uniseg v0.4.7 // indirect
23-
github.com/savannahostrowski/tree-bubble v0.0.0-20230724043728-d7bb06a8a67e // indirect
24-
golang.org/x/sync v0.1.0 // indirect
28+
github.com/sahilm/fuzzy v0.1.1 // indirect
29+
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
30+
golang.org/x/sync v0.11.0 // indirect
2531
golang.org/x/sys v0.36.0 // indirect
26-
golang.org/x/term v0.6.0 // indirect
2732
golang.org/x/text v0.3.8 // indirect
2833
)

go.sum

Lines changed: 28 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,61 @@
1+
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
2+
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
13
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
24
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
3-
github.com/charmbracelet/bubbles v0.16.1 h1:6uzpAAaT9ZqKssntbvZMlksWHruQLNxg49H5WdeuYSY=
4-
github.com/charmbracelet/bubbles v0.16.1/go.mod h1:2QCp9LFlEsBQMvIYERr7Ww2H2bA7xen1idUDIzm/+Xc=
5+
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
6+
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
57
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
68
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
7-
github.com/charmbracelet/bubbletea v0.24.2 h1:uaQIKx9Ai6Gdh5zpTbGiWpytMU+CfsPp06RaW2cx/SY=
8-
github.com/charmbracelet/bubbletea v0.24.2/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg=
9-
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
10-
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
11-
github.com/charmbracelet/colorprofile v0.3.3 h1:DjJzJtLP6/NZ8p7Cgjno0CKGr7wwRJGxWUwh2IyhfAI=
12-
github.com/charmbracelet/colorprofile v0.3.3/go.mod h1:nB1FugsAbzq284eJcjfah2nhdSLppN2NqvfotkfRYP4=
13-
github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E=
14-
github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c=
9+
github.com/charmbracelet/bubbletea v1.3.4 h1:kCg7B+jSCFPLYRA52SDZjr51kG/fMUEoPoZrkaDHyoI=
10+
github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo=
11+
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
12+
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
1513
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
1614
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
17-
github.com/charmbracelet/x/ansi v0.11.2 h1:XAG3FSjiVtFvgEgGrNBkCNNYrsucAt8c6bfxHyROLLs=
18-
github.com/charmbracelet/x/ansi v0.11.2/go.mod h1:9tY2bzX5SiJCU0iWyskjBeI2BRQfvPqI+J760Mjf+Rg=
19-
github.com/charmbracelet/x/cellbuf v0.0.14 h1:iUEMryGyFTelKW3THW4+FfPgi4fkmKnnaLOXuc+/Kj4=
20-
github.com/charmbracelet/x/cellbuf v0.0.14/go.mod h1:P447lJl49ywBbil/KjCk2HexGh4tEY9LH0/1QrZZ9rA=
21-
github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
22-
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
23-
github.com/clipperhouse/displaywidth v0.6.1 h1:/zMlAezfDzT2xy6acHBzwIfyu2ic0hgkT83UX5EY2gY=
24-
github.com/clipperhouse/displaywidth v0.6.1/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o=
25-
github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
26-
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
27-
github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4=
28-
github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
29-
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY=
30-
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
31-
github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/qqsc=
32-
github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
15+
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
16+
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
17+
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
18+
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
19+
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
20+
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
21+
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
22+
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
3323
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
3424
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
25+
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
26+
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
3527
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
3628
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
37-
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
38-
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
3929
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
4030
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
4131
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
4232
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
43-
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
4433
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
4534
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
46-
github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
47-
github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
4835
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
4936
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
5037
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
5138
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
52-
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
53-
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
54-
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
55-
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
5639
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
5740
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
58-
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
5941
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
6042
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
6143
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
62-
github.com/savannahostrowski/tree-bubble v0.0.0-20230724043728-d7bb06a8a67e h1:nktxNPbFDw48XE8CImkdkjFu68+kmMf0sC+W+v46uKI=
63-
github.com/savannahostrowski/tree-bubble v0.0.0-20230724043728-d7bb06a8a67e/go.mod h1:inJ/hStD+7ynR44VY0B/Ebp9U2TK1QFD4NavPTm8BsY=
44+
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
45+
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
6446
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
6547
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
66-
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
67-
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
68-
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
69-
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
48+
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
49+
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
50+
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
51+
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
7052
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
71-
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
7253
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
7354
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
7455
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
75-
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
76-
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
77-
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
78-
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
79-
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
80-
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
8156
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
8257
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
83-
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
84-
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
58+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
59+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
60+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
61+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/check/precheck.go

Lines changed: 176 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ import (
88
"os/user"
99
"runtime"
1010
"strings"
11+
12+
tea "github.com/charmbracelet/bubbletea"
13+
"github.com/shubh-io/dockmate/internal/config"
14+
"github.com/shubh-io/dockmate/internal/tui"
1115
)
1216

1317
// ============================================================================
@@ -29,8 +33,60 @@ const (
2933
DockerDaemonNotRunning
3034
DockerPermissionDenied
3135
DockerGroupNotRefreshed
36+
PodmanNotInstalled
37+
PodmanServiceNotRunning
3238
)
3339

40+
// Runtime Selection
41+
42+
// checks if the runtime is properly configured
43+
44+
// Returns false if runtime is set to something other than "docker" or "podman" or config just doesn't exists
45+
46+
func isRuntimeConfigured() bool {
47+
cfg, err := config.Load()
48+
if err != nil {
49+
return false
50+
}
51+
52+
runtimeType := strings.TrimSpace(strings.ToLower(cfg.Runtime.Type))
53+
return (runtimeType == "docker" || runtimeType == "podman") && runtimeType != "" && runtimeType != "auto"
54+
}
55+
56+
// promptRuntimeSelection shows the runtime selector TUI and saves selection
57+
58+
func promptRuntimeSelection() error {
59+
// show runtime selection TUI
60+
runtimeSelector := tui.NewRuntimeSelectionModel()
61+
program := tea.NewProgram(runtimeSelector, tea.WithAltScreen())
62+
63+
finalModel, err := program.Run()
64+
if err != nil {
65+
return fmt.Errorf("runtime selection failed: %w", err)
66+
}
67+
68+
rsModel, ok := finalModel.(tui.RuntimeSelectionModel)
69+
if !ok {
70+
return fmt.Errorf("invalid model type returned")
71+
}
72+
73+
selectedRuntime := strings.TrimSpace(rsModel.GetChoice())
74+
if selectedRuntime == "" {
75+
return fmt.Errorf("no runtime selected")
76+
}
77+
78+
// Load current config and update runtime
79+
cfg, _ := config.Load()
80+
cfg.Runtime.Type = selectedRuntime
81+
82+
// Save updated config
83+
if err := cfg.Save(); err != nil {
84+
return fmt.Errorf("failed to save runtime selection: %w", err)
85+
}
86+
87+
return nil
88+
}
89+
3490
// ============================================================================
3591
// PreCheck Functions
3692
// ============================================================================
@@ -83,6 +139,40 @@ func getDockerRestartCommand() string {
83139
return "sudo service docker restart"
84140
}
85141

142+
// getPodmanStartCommand returns their start command per platform (peak user case handling lol)
143+
144+
func getPodmanStartCommand() string {
145+
if runtime.GOOS == "darwin" {
146+
return "podman machine start"
147+
}
148+
149+
if commandExists("systemctl") {
150+
return "systemctl --user start podman.socket"
151+
}
152+
153+
if commandExists("podman") {
154+
return "podman system service -t 0 &"
155+
}
156+
157+
return "podman machine start"
158+
}
159+
160+
// getPodmanErrorMessage provides platform-specific guidance for starting Podman
161+
func getPodmanErrorMessage() string {
162+
cmd := getPodmanStartCommand()
163+
164+
switch runtime.GOOS {
165+
case "darwin":
166+
return fmt.Sprintf("Podman machine not running.\n\nQuick fix:\n %s\n\nIf machine doesn't exist:\n podman machine init\n podman machine start\n\nHelp: https://docs.podman.io/", cmd)
167+
168+
case "linux":
169+
return fmt.Sprintf("Podman not accessible.\n\nTry:\n %s\n \nOr check if rootless is set up:\n podman info\n\nHelp: https://github.com/containers/podman/blob/main/troubleshooting.md", cmd)
170+
171+
}
172+
173+
return fmt.Sprintf("Start Podman: %s\nHelp: https://docs.podman.io/", cmd)
174+
}
175+
86176
// checks if the 'docker' group exists on the system and anchor before docker to help find group that 'starts with' docker
87177
// On macOS, Docker Desktop doesn't use groups, so this always returns false
88178
func doesDockerGroupExist() bool {
@@ -241,6 +331,21 @@ func checkDockerInstalled() PreCheckResult {
241331
return PreCheckResult{Passed: true}
242332
}
243333

334+
// check if podman is installed in PATH
335+
func checkPodmanInstalled() PreCheckResult {
336+
_, err := exec.LookPath("podman")
337+
if err != nil {
338+
return PreCheckResult{
339+
Passed: false,
340+
ErrorType: PodmanNotInstalled,
341+
ErrorMessage: "Podman is not installed or not found in PATH",
342+
SuggestedAction: "Please install Podman to use this runtime.\n\n" +
343+
"Installation guide: https://podman.io/docs/installation",
344+
}
345+
}
346+
return PreCheckResult{Passed: true}
347+
}
348+
244349
func checkDockerDaemon() PreCheckResult {
245350
cmd := exec.Command("docker", "info")
246351
var stderr bytes.Buffer
@@ -357,6 +462,26 @@ func checkDockerDaemon() PreCheckResult {
357462
}
358463
}
359464

465+
func checkPodmanService() PreCheckResult {
466+
cmd := exec.Command("podman", "info")
467+
var stderr bytes.Buffer
468+
cmd.Stderr = &stderr
469+
470+
err := cmd.Run()
471+
if err == nil {
472+
return PreCheckResult{Passed: true}
473+
}
474+
475+
stderrOutput := stderr.String()
476+
477+
return PreCheckResult{
478+
Passed: false,
479+
ErrorType: PodmanServiceNotRunning,
480+
ErrorMessage: fmt.Sprintf("Podman service is not running or not reachable.\n\nPodman error:\n%s", stderrOutput),
481+
SuggestedAction: getPodmanErrorMessage(),
482+
}
483+
}
484+
360485
// Helper function to check if daemon is actually running
361486
func isDaemonRunning() bool {
362487
cmd := exec.Command("docker", "info")
@@ -365,16 +490,59 @@ func isDaemonRunning() bool {
365490
}
366491

367492
func RunPreChecks() PreCheckResult {
368-
// Check 1: Is Docker even installed?
369-
result := checkDockerInstalled()
370-
if !result.Passed {
371-
return result
493+
// Check - Is runtime configured? If not, prompt user
494+
if !isRuntimeConfigured() {
495+
err := promptRuntimeSelection()
496+
if err != nil {
497+
return PreCheckResult{
498+
Passed: false,
499+
ErrorType: NoError,
500+
ErrorMessage: fmt.Sprintf("Failed to select runtime: %v", err),
501+
SuggestedAction: "If you want to Change the runtime, run: \n dockmate --runtime \n",
502+
}
503+
}
504+
}
505+
506+
cfg, _ := config.Load()
507+
runtimeType := strings.TrimSpace(strings.ToLower(cfg.Runtime.Type))
508+
if runtimeType == "" {
509+
runtimeType = "docker"
372510
}
373511

374-
// Check 2: Can we connect to Docker daemon
375-
result = checkDockerDaemon()
376-
if !result.Passed {
377-
return result
512+
switch runtimeType {
513+
case "podman":
514+
result := checkPodmanInstalled()
515+
if !result.Passed {
516+
result.SuggestedAction += "\n\nOr If you want to Change the runtime to docker, run: \n dockmate --runtime \n"
517+
return result
518+
}
519+
520+
result = checkPodmanService()
521+
if !result.Passed {
522+
result.SuggestedAction += "\n\nOr If you want to Change the runtime to docker, run: \n dockmate --runtime \n"
523+
return result
524+
}
525+
526+
case "docker", "auto":
527+
result := checkDockerInstalled()
528+
if !result.Passed {
529+
result.SuggestedAction += "\n\nOr If you want to Change the runtime to podman, run: \n dockmate --runtime \n"
530+
return result
531+
}
532+
533+
result = checkDockerDaemon()
534+
if !result.Passed {
535+
result.SuggestedAction += "\n\nOr If you want to Change the runtime to podman, run: \n dockmate --runtime \n"
536+
return result
537+
}
538+
539+
default:
540+
return PreCheckResult{
541+
Passed: false,
542+
ErrorType: NoError,
543+
ErrorMessage: fmt.Sprintf("Unsupported runtime type: %s", runtimeType),
544+
SuggestedAction: "Please choose docker or podman using: \n dockmate --runtime \n",
545+
}
378546
}
379547

380548
return PreCheckResult{Passed: true}

0 commit comments

Comments
 (0)