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
|
// 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.refresh(); }
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: ""
Text {
width: col.width
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 reopen this page."
color: Sbb.reachable || Sbb.busy ? Theme.subtext : Theme.yellow
font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 }
}
Column {
width: col.width
spacing: 6
enabled: Sbb.reachable
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
}
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 = "";
}
}
}
}
}
}
}
}
|