forked from bazaar-org/bazaar
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathoverview.org
More file actions
587 lines (510 loc) · 20.7 KB
/
Copy pathoverview.org
File metadata and controls
587 lines (510 loc) · 20.7 KB
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
#+title: Bazaar Overview
#+author: Adam Masciola (kolunmi)
This document is intended for distributors of Bazaar to learn how to
configure the application.
** Features
Here is a short list of some of the things Bazaar can do, beyond the
basics of managing software through the GUI:
- Queue an arbitrary number of transactions (a catch-all term for
installations, updates, and removals) during which you may close all
windows or continue to append new transactions freely
- Display a "Curated" page which you may extensively customize with
YAML, as will be discussed later. This is a way to highlight
applications which you believe might be of interest.
- Curated configuration files are constantly monitored for
filesystem events, meaning you can update them and see the changes
immediate reflected in the GUI
- You can have any number of curated configuration files; they will
concatenate in the GUI in the order they were provided
- Access data from [[https://flathub.org/][flathub]], such as the latest or most popular
applications
- Filter through applications very quickly using a very forgiving
search routine
- For instance, if a user quickly types =ikscep= into the search
field, Inkscape will still appear as the top result.
- Run in the background and respond to desktop search queries with
application info, using the same search routine as in-application
- GNOME will work out of the box, as Bazaar implements the
=org.gnome.Shell.SearchProvider2= dbus interface
- KDE Plasma will require a [[https://github.com/ublue-os/krunner-bazaar][krunner plugin]]
- Hide applications you do not want users to see with blocklists,
which is useful for discouraging the use of certain packages which
you deem to be broken.
- Manage an arbitrary amount of windows and keep them synchronized
- Communicate with, and invoke operations on, the main daemon through
the command line
** CLI Usage
You can start the bazaar daemon like this:
#+begin_example
bazaar [ARGS] [PACKAGE PATH/URI]
#+end_example
To avoid spawning a window, use:
#+begin_example
bazaar --no-window [ARGS] [PACKAGE PATH/URI]
#+end_example
=[PACKAGE PATH/URI]= could be a =.flatpakref= file. flatpak+https and
regular https is supported.
** Comptime Vars
Bazaar provides a few compile time meson options:
- =hardcoded_main_config_path=: Embeds a path to a main configuration file into
Bazaar. If this is not defined at compile time, Bazaar will never attempt to
read a main config. See the "Hooks" section of this document to see an example
config file.
THESE NEXT TWO OPTIONS ARE DEPRECATED. GOING FORWARD, PLEASE USE THE MAIN CONFIG
TO SPECIFY BLOCKLIST PATHS AND CURATED CONFIG PATHS.
- =hardcoded_blocklist_path=: Embeds a path to a blocklist into Bazaar
which, if possible, will always be read with highest priority.
- =hardcoded_content_config_path=: Embeds a path to a curated YAML
configuration file into Bazaar which, if possible, will always be
read with highest priority
** Curated Configurations
If Bazaar is provided a non-zero amount of curated configs, an extra
tab will appear on the window's header bar called "Curated". This
section is intended for distributors to curate applications for users
with a customizable interface. Curated configs are YAML files. They
are constantly monitored by Bazaar for filesystem events, so when the
config changes, Bazaar will automatically reload the content.
Right now, curated configs are essentially composed of a list of
"sections" which appear stacked on top of each other inside of a
scrollable viewport in the order they appear in the YAML. Each section
has certain properties you can customize, like a title, an image
banner URI, and of course a list of appids. Bazaar maps the appids you
provide to the best matching "entry group" from the table of
applications it was able to pull from remote sources (Simply put, an
entry group in Bazaar is a collection of applications which share the
same appid but come from different sources or installations). The
entry group has a designated "ui entry" which was previously
determined in the refresh process to have the most useful content
associated with it as it pertains to presenting things like icons,
descriptions, screenshots, etc to the user. When the user selects the
app in the section, they are brought to a "full view" where they can
see a bunch of information stored inside or referenced by the ui entry
and choose to invoke transactions on the entry group, like
installation or removal.
Additionally, curated configs allow you to define a css block from
which you can reference classes inside sections and change the way gtk
renders the content.
Here is a basic curated config:
#+begin_src yaml
# Some css names at your disposal:
# - banner
# - banner-text
# - banners
# - description
# - subtitle
# - title
# - app-tile
# - app-tile-title
# - app-tile-verified-check
# - app-tile-description
css: |
.main-section {
margin: 15px;
border-radius: 25px;
}
.main-section banner-text {
margin: 15px;
color: white;
}
.background-1 {
background: linear-gradient(45deg, #170a49, #52136c);
}
.background-1 title {
border-bottom: 5px solid white;
}
.background-1 app-tile > button {
background-color: alpha(white, 0.1);
}
.background-1 app-tile > button:hover {
background-color: alpha(var(--accent-bg-color), 0.5);
}
.background-2 {
background: linear-gradient(75deg, #51263c, #7104a9);
}
.background-2 app-tile > button:focus {
background-color: alpha(var(--accent-bg-color), 0.5);
}
.background-2 app-tile-verified-check {
color: orange;
}
rows:
- sections:
- expand-horizontally: true
category:
title: "My Favorite Apps"
subtitle: "These are really good and you should download them!"
# can be https as well
banner: file:///home/kolunmi/banner-1.jxl
# can be "fill", "contain", "cover", or "scale-down"
# see https://docs.gtk.org/gtk4/enum.ContentFit.html
banner-fit: contain
# can be "fill", "start", "end", or "center"
# see https://docs.gtk.org/gtk4/enum.Align.html
# halign -> "horizontal alignment"
banner-text-halign: start
# valign -> "vertical alignment"
banner-text-valign: center
# "The horizontal alignment of the label text inside its size
# allocation."
# see https://docs.gtk.org/gtk4/property.Label.xalign.html
banner-text-label-xalign: 0.0
# appid list
appids:
- com.usebottles.bottles
- io.mgba.mGBA
- net.pcsx2.PCSX2
- org.blender.Blender
- org.desmume.DeSmuME
- org.duckstation.DuckStation
- org.freecad.FreeCAD
# reference the classes we defined earlier
classes:
- main-section
- background-1
# The `classes` key (above) is for styling which we want to apply
# all the time. If you want a style class to only be active in
# light or dark mode, use `light-classes` or `dark-classes`:
light-classes:
- light-section
dark-classes:
- dark-section
- sections:
- category:
title: "Some more awesome apps!"
subtitle: "These are also pretty cool"
banner: file:///home/kolunmi/banner-2.png
banner-fit: contain
banner-text-halign: end
banner-text-valign: center
banner-text-label-xalign: 1.0
appids:
- org.gimp.GIMP
- org.gnome.Builder
- org.gnome.Loupe
- org.inkscape.Inkscape
classes:
- main-section
- background-2
#+end_src
** Blocklists
Blocklists are a way to ensure that users will never interact with a certain
application inside Bazaar. There are two kinds of blocklists supported by
Bazaar:
YAML files, containing special rules, priorities, and regex:
#+begin_src yaml
blocklists:
- priority: 0
block-regex:
# block all ids matching this regex unconditionally
- com\.place\..*
- priority: -1 # lower number = higher priority
conditions:
- match-locale:
# only apply this rule if we have the Arabic locale
regex: ar
allow:
- com.place.App3
- com.place.App5
allow-regex:
- com\.place\..*\.ar
- priority: -1
conditions:
- match-locale:
regex: en.*
# invert the result of this condition; so all locales which don't match
# the regex
post-process: invert
- match-envvar:
var: PATH
regex: .*/usr/local/bin.*
block:
- com.other.App1
allow:
- com.place.App1
- com.place.App2
#+end_src
Simple plain text files with newline-separated appids:
#+begin_example
com.jetbrains.CLion
com.valvesoftware.Steam
io.neovim.nvim
net.lutris.Lutris
#+end_example
Note: blocklists will only prevent certain appids from appearing in
Bazaar. They do not stop the user from installing anything with the
flatpak cli, for example.
** Hooks
Hooks are an advanced feature of Bazaar. In essence, they allow you to
programmatically react to events and define dialogs with which you can
query user input. Currently, the only events you can subscribe to are
the "before-transaction" and "after-transaction" events:
- =before-transaction=: run the hook right before a transaction is
scheduled to begin
- =after-transaction=: run the hook after a transaction successfully
completes
Hooks are run like a signal emission. After an event occurs, hooks
that are found to be of the appropriate type are evaluated in an order
of priority. Higher priority hooks have the ability to stop the
emission from propagating further downwards. In the case of some
events, like "before-transaction", a hook can also hint to Bazaar some
action to take, in this case whether the transaction should be
aborted.
A shell snippet which is defined by you is evaluated with =/bin/sh -c=
multiple times over the course of a hook's execution. An invocation of
the shell snippet is referred to as a "stage". Your shell snippet
(which of course could just invoke another script written in whatever
language you prefer) will be provided a number of environment
variables which together will describe the current stage. Your snippet
must react accordingly by printing a response to stdout, which Bazaar
will read back.
This opens up a lot of possibilities for customization; here are a few
examples:
- You would like a certain appid to be added to steam after the user
installs it, so you register a hook on "after-transaction" to query
the user's permission with a custom dialog. If they confirm, your
script will go forward with the task of setting up a steam shortcut.
- You would like to prevent users from installing a certain appid, as
some other method of installation, such as a system package, would
provide a superior experience. A blocklist could achieve this, but
you don't like the idea of hiding anything from the user. A hook
subscribed to the "before-transaction" event could issue a warning
and ask for extra confirmation. If the user decides to listen to the
warning, you can signal to Bazaar that the transaction should be
aborted.
Here is an overview of the environment variables the shell snippet
will receive:
- =BAZAAR_HOOK_INITIATED_UNIX_STAMP=: the unix timestamp in seconds at
which this hook was first invoked (the number of seconds that have
elapsed since 1970-01-01 00:00:00 UTC)
- =BAZAAR_HOOK_INITIATED_UNIX_STAMP_USEC=: the unix timestamp in
microseconds at which this hook was first invoked (the number of
microseconds that have elapsed since 1970-01-01 00:00:00 UTC)
- =BAZAAR_HOOK_STAGE_IDX=: the number of stages this hook has run so
far
- =BAZAAR_HOOK_ID=: the value of the "id" mapping
- =BAZAAR_HOOK_TYPE=: the value of the "when" mapping
- =BAZAAR_HOOK_WAS_ABORTED=: "true" if a dialog aborted the hook
- =BAZAAR_HOOK_DIALOG_ID=: if applicable, the id of the current dialog
- =BAZAAR_HOOK_DIALOG_RESPONSE_ID=: if applicable, the user response
given through the current dialog
- =BAZAAR_TS_APPID=: if applicable, the appid of the entry Bazaar is
currently dealing with
- =BAZAAR_TS_TYPE=: if applicable, the type of transaction being
run. Can be "install", "update", or "removal".
- =BAZAAR_HOOK_STAGE=: the stage at which the hook is running. This
will indicate what the shell body is instructed to do at this
time. The shell body must respond by outputting to stdout with a
valid answer; the structure of a valid answer will depend on the
stage, and if the structure is not valid the hook will be
abandoned. The shell body might be run multiple times by Bazaar over
the course of a hook with this variable set to differing values in
order know how to orchestrate events in the UI, so the shell body
must be able to branch depending on the value. The value may be any
of the following:
- =setup=: the hook is starting. Respond with "ok" to continue the
execution of this hook, or "pass" to skip it and move on to the
next registered hook
- =setup-dialog= Bazaar is ready to ask the user a question with one
of the dialogs you've defined inside the "dialogs"
mapping. =BAZAAR_HOOK_DIALOG_ID= will tell you which one. Respond
with "ok" to spawn the dialog, or "pass" to skip the dialog.
- =teardown-dialog= Bazaar has received input from the user after
asking them a question with one of the dialogs you've defined
inside the "dialogs" mapping. =BAZAAR_HOOK_DIALOG_ID= will tell
you which one. =BAZAAR_HOOK_DIALOG_RESPONSE_ID= will tell you the
response the user chose. Respond with "ok" to continue, or "abort"
to stop the execution of this hook.
- =catch= One of your dialogs has aborted. This is your chance to
handle the error. Respond with "recover" to continue, or "abort"
to confirm that the execution of this hook should indeed skip to
the teardown stage.
- =action= Everything so far has gone according to plan, so it is
time to take whatever external action this hook exists for. Bazaar
requires no response at this time.
- =teardown= The hook is cleaning up. Respond with "continue" to
propagate the signal emission to lower priority hooks, or "stop"
to indicate the emission should stop. Alternatively, if this hook
type should hint to Bazaar an action to take (such as the
"before-transaction" hook), respond with "confirm" to hint that
the action should be taken, or "deny" to prevent the action from
being taken. Both "confirm" and "deny" imply the effect of "stop",
and "stop" implies "confirm".
Hooks are defined in the main yaml config as indicated by the
=hardcoded_main_config_path= comptime var. Here is a basic example
demonstrating how to define a hook:
#+begin_src yaml
yaml-blocklist-paths:
- /path/to/yaml/blocklist.yaml
- /path/to/another/yaml/blocklist.yaml
txt-blocklist-paths:
- /path/to/txt/blocklist.txt
- /path/to/another/txt/blocklist.txt
curated-config-paths:
- /path/to/yaml/file.yaml
- /path/to/another/yaml/file.yaml
hooks:
- id: my-hook
when: before-transaction
dialogs:
- id: my-dialog-1
title: "Please confirm"
# If true, render inline markup commands
# see https://docs.gtk.org/Pango/pango_markup.html
body-use-markup: true
body: "This application is an official <a href=\"https://www.gnome.org/\">GNOME</a> app, which is <b>important</b> because..."
# Determines which option will be assumed if the user hits the
# escape key or otherwise cancels the dialog
default-response-id: no
options:
- id: no
string: "Don't install"
# can be "destructive" or "suggested" or omit for no
# styling
style: destructive
- id: yes
string: "Next"
style: suggested
- id: my-dialog-2
title: "Double check"
body-use-markup: false
body: "Here are some other considerations..."
default-response-id: no
options:
- id: no
string: "Don't install"
style: destructive
- id: yes
string: "Continue with install"
style: suggested
shell: |
case "$BAZAAR_HOOK_STAGE" in
setup)
if [ "$BAZAAR_TS_TYPE" = install ]; then
case "$BAZAAR_TS_APPID" in
org\.gnome\.*)
echo 'ok' ;;
,*) echo 'pass' ;;
esac
else
echo 'pass'
fi
;;
setup-dialog)
echo 'ok'
;;
teardown-dialog)
case "$BAZAAR_HOOK_DIALOG_RESPONSE_ID" in
yes) echo 'ok' ;;
,*) echo 'abort' ;;
esac
;;
catch)
echo 'abort'
;;
action)
;;
teardown)
[ "$BAZAAR_HOOK_WAS_ABORTED" = true ] && echo 'deny' || echo 'confirm'
;;
esac
#+end_src
In this example, if this user tries to install an appid that starts
with =org.gnome.=, we present two dialogs asking for confirmation. If
they decide to select a response with an id other than =yes=, abort
the transaction.
*** More realistic example
=hardcoded_main_config_path=:
#+begin_src yaml
hooks:
- id: handle-jetbrains
when: before-transaction
dialogs:
- id: jetbrains-warning
title: >-
Jetbrains IDEs are not supported in this format
# If true, render inline markup commands in body; see
# https://docs.gtk.org/Pango/pango_markup.html
body-use-markup: true
body: >-
This is a <a href="https://www.jetbrains.com/">Jetbrains</a>
application and is not officially supported on Flatpak. We
recommend using the Toolbox app to manage Jetbrains IDEs.
# Determines which option will be assumed if the user hits the
# escape key or otherwise cancels the dialog
default-response-id: cancel
options:
- id: cancel
string: "Cancel"
- id: goto-web
string: "Download Jetbrains Toolbox"
# can be "destructive" or "suggested" or omit for no
# styling
style: suggested
shell: exec /absolute/path/to/bazaar-jetbrains-hook.bash
#+end_src
=/absolute/path/to/bazaar-jetbrains-hook.bash=:
#+begin_src bash
#!/usr/bin/env bash
handle_setup_stage() {
# only proceed if the user is installing something
if [ "$BAZAAR_TS_TYPE" = install ]; then
case "$BAZAAR_TS_APPID" in
com\.jetbrains\.*)
# since the appid belongs to jetbrains, we continue
# with the hook
echo 'ok'
;;
,*)
# otherwise, skip this hook
echo 'pass'
;;
esac
else
echo 'pass'
fi
}
handle_setup_dialog_stage() {
# we don't need to do anything here right now, just let Bazaar
# know we should continue setting up the dialog
echo 'ok'
}
handle_teardown_dialog_stage() {
case "$BAZAAR_HOOK_DIALOG_RESPONSE_ID" in
goto-web)
# if the user pressed "Download Jetbrains Toolbox",
# continue
echo 'ok'
;;
,*)
# otherwise, let's not do anything
echo 'abort'
;;
esac
}
handle_catch_stage() {
# this only happens if the `teardown-dialog` stage echoed "abort",
# we could echo "recover" at this point to still go to the
# `action` stage, but we have no reason to do that right now
echo 'abort'
}
handle_action_stage() {
# this is where we do the thing! it is important to use `nohup`
# here so bazaar doesn't hang
nohup xdg-open 'https://www.jetbrains.com/toolbox-app/'
}
handle_teardown_stage() {
# Let's always prevent the user from installing Jetbrains stuff
echo 'deny'
}
# Branch based on the stage
case "$BAZAAR_HOOK_STAGE" in
setup) handle_setup_stage ;;
setup-dialog) handle_setup_dialog_stage ;;
teardown-dialog) handle_teardown_dialog_stage ;;
catch) handle_catch_stage ;;
action) handle_action_stage ;;
teardown) handle_teardown_stage ;;
esac
# exit successfully
exit 0
#+end_src