aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/modules/sbbuilder/SbbVmModule.qml
blob: 45c72160c1c9ca190757f8d365be00d25044aceb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

import QtQuick
import "../.."
import "../qtmaildir"

// sbb-remote's config on the build VM, through the helper's config-get and
// config-set. The helper reads it on every call, so a save applies to the
// next one.
Module {
    name: "sbb-vm"
    label: "Build VM"
    // nf-fa-server, present in Inconsolata Nerd Font.
    icon: "\uf233"
    settings: true
    group: "SB Builder"
    dirty: Sbb.vm.dirty
    keywords: ["sb-builder", "sbb-remote", "slackrepo", "hints", "overlays", "manifests", "phantom", "gpg"]
    readonly property var fields: [
        ["state_dir", "State"], ["repo_dir", "SlackBuilds repo"], ["upstream_branch", "Upstream branch"],
        ["slackrepo_db", "slackrepo database"], ["sbpull_script", "sbpull script"], ["overlays", "Overlays"],
        ["slackrepo_repo", "slackrepo repo"], ["hintdir", "Hints"], ["default_hintdir", "Default hints"],
        ["genreprc", "genreprc"], ["slackrepo_logdir", "slackrepo logs"], ["phantom_deps_file", "Phantom deps"]]
    searchItems: fields.map(f => ({ text: f[1], key: "/" + f[0] }))
        .concat(Sbb.vm.manifests.map(p => ({ text: p + " manifest", key: "manifests/" + p })))
    function refresh() { Sbb.fetch(false); }

    page: Component {
        Page {
            title: "SB Builder: build VM"
            actions: Component {
                SaveBar {
                    dirty: Sbb.vm.dirty; valid: Sbb.vm.valid && Sbb.reachable; error: Sbb.vm.error
                    busy: Sbb.busy
                    onSave: Sbb.saveVm(); onDiscard: Sbb.vm.discard()
                }
            }
            Column {
                id: col
                width: parent.width
                spacing: 6
                readonly property var st: Sbb.vm
                property string confirming: ""
                Item {
                    width: col.width
                    height: Math.max(status.implicitHeight, reload.height)
                    Text {
                        id: status
                        anchors { left: parent.left; right: reload.left; rightMargin: 8; verticalCenter: parent.verticalCenter }
                        wrapMode: Text.Wrap
                        text: Sbb.busy ? "Asking the VM..."
                            : Sbb.reachable ? Sbb.vmPath + " on the VM. The helper checks a save and keeps the old file as .bak."
                            : "The VM did not answer, so nothing here can change. Start it, then Reload."
                        color: Sbb.reachable || Sbb.busy ? Theme.subtext : Theme.yellow
                        font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 }
                    }
                    Button {
                        id: reload
                        anchors { right: parent.right; verticalCenter: parent.verticalCenter }
                        text: "Reload"
                        enabled: !Sbb.busy
                        onClicked: Sbb.fetch(false)
                    }
                }

                Column {
                    width: col.width
                    spacing: 6
                    // Read-only while a save runs too: typing then would be lost or mis-recorded.
                    enabled: Sbb.reachable && !Sbb.busy
                    opacity: Sbb.reachable ? 1 : 0.5
                    Repeater {
                        model: [
                            ["Paths"],
                            ["state_dir", "State", "Job logs and the lock."],
                            ["repo_dir", "SlackBuilds repo", ""],
                            ["slackrepo_db", "slackrepo database", ""],
                            ["slackrepo_logdir", "slackrepo logs", ""],
                            ["sbpull_script", "sbpull script", ""],
                            ["genreprc", "genreprc", "Its REPOSOWNERGPG names the signing key."],
                            ["Repository"],
                            ["upstream_branch", "Upstream branch", ""],
                            ["overlays", "Overlays", "Separated by spaces, in search order."],
                            ["slackrepo_repo", "slackrepo repo", ""],
                            ["Hints"],
                            ["hintdir", "Hints", ""],
                            ["default_hintdir", "Default hints", "Searched after Hints when set."],
                            ["phantom_deps_file", "Phantom deps", "Deps -current ships, one per line."]]
                        delegate: Loader {
                            id: row
                            required property var modelData
                            width: col.width
                            sourceComponent: row.modelData.length === 1 ? heading : field
                            Component { id: heading; Heading { text: row.modelData[0] } }
                            Component {
                                id: field
                                Setting { store: col.st; section: ""; key: row.modelData[0]; label: row.modelData[1]
                                          hint: row.modelData[2]; placeholder: col.st.placeholder("", row.modelData[0]) }
                            }
                        }
                    }

                    Heading { text: "Bundled deps" }
                    Text {
                        width: col.width
                        wrapMode: Text.Wrap
                        text: "A package's upstream deps list; {VERSION} is the new version. A hint update moves the package's extra downloads to the versions listed there."
                        color: Theme.subtext
                        font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 }
                    }
                    Repeater {
                        model: col.st.manifests
                        delegate: Item {
                            id: mrow
                            required property string modelData
                            objectName: "manifests/" + modelData
                            width: col.width
                            height: url.height
                            Setting {
                                id: url
                                width: parent.width - del.width - 8
                                store: col.st; section: "manifests"; key: mrow.modelData; label: mrow.modelData
                                placeholder: "a URL; Remove deletes the row"
                            }
                            Button {
                                id: del
                                anchors { right: parent.right; top: parent.top; topMargin: 4 }
                                danger: true
                                text: col.confirming === mrow.modelData ? "Confirm" : "Remove"
                                onClicked: {
                                    if (col.confirming === mrow.modelData) { col.confirming = ""; col.st.remove("manifests", mrow.modelData); }
                                    else col.confirming = mrow.modelData;
                                }
                            }
                        }
                    }
                    Item {
                        width: col.width
                        height: 34
                        Rectangle {
                            id: pkgBox
                            anchors { left: parent.left; right: add.left; rightMargin: 8; top: parent.top; bottom: parent.bottom }
                            radius: 8
                            color: Theme.surface
                            TextInput {
                                id: pkg
                                activeFocusOnTab: true
                                anchors { fill: parent; leftMargin: 10; rightMargin: 10 }
                                verticalAlignment: TextInput.AlignVCenter
                                clip: true
                                selectByMouse: true
                                color: Theme.text
                                font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 }
                                onAccepted: add.clicked(null)
                                Text {
                                    anchors.verticalCenter: parent.verticalCenter
                                    visible: parent.text === ""
                                    text: "package name, then its URL in the new row"
                                    color: Theme.overlay
                                    font: parent.font
                                }
                            }
                        }
                        Button {
                            id: add
                            anchors { right: parent.right; verticalCenter: parent.verticalCenter }
                            text: "Add"
                            enabled: /^[A-Za-z0-9_.+-]+$/.test(pkg.text) && !col.st.manifests.includes(pkg.text)
                            onClicked: {
                                if (!add.enabled) return;
                                col.st.put("manifests", pkg.text, "https://");
                                pkg.text = "";
                            }
                        }
                    }
                }
            }
        }
    }
}