1
1
#!/usr/bin/env python3
2
2
# -*- coding: utf-8 -*-
3
3
# pylint: disable=wrong-import-position,import-error
4
+ import argparse
4
5
import logging
5
6
import time
6
7
10
11
from qubes_config .widgets .gtk_utils import load_icon_at_gtk_size , load_theme , \
11
12
show_dialog_with_icon , RESPONSES_OK
12
13
from qui .updater .progress_page import ProgressPage
13
- from qui .updater .updater_settings import Settings
14
+ from qui .updater .updater_settings import Settings , OverridenSettings
14
15
from qui .updater .summary_page import SummaryPage
15
16
from qui .updater .intro_page import IntroPage
16
17
@@ -33,14 +34,15 @@ class QubesUpdater(Gtk.Application):
33
34
LOGPATH = '/var/log/qubes/qui.updater.log'
34
35
LOG_FORMAT = '%(asctime)s %(message)s'
35
36
36
- def __init__ (self , qapp ):
37
+ def __init__ (self , qapp , cliargs ):
37
38
super ().__init__ (
38
39
application_id = "org.gnome.example" ,
39
40
flags = Gio .ApplicationFlags .FLAGS_NONE
40
41
)
41
42
self .qapp = qapp
42
43
self .primary = False
43
44
self .connect ("activate" , self .do_activate )
45
+ self .cliargs = cliargs
44
46
45
47
log_handler = logging .FileHandler (
46
48
QubesUpdater .LOGPATH , encoding = 'utf-8' )
@@ -49,13 +51,15 @@ def __init__(self, qapp):
49
51
50
52
self .log = logging .getLogger ('vm-update.agent.PackageManager' )
51
53
self .log .addHandler (log_handler )
52
- self .log .setLevel ("DEBUG" )
54
+ self .log .setLevel (self . cliargs . log )
53
55
54
56
def do_activate (self , * _args , ** _kwargs ):
55
57
if not self .primary :
56
58
self .perform_setup ()
57
59
self .primary = True
58
60
self .hold ()
61
+ elif len (self .intro_page .get_vms_to_update ()) == 0 :
62
+ self .exit_updater ()
59
63
else :
60
64
self .main_window .present ()
61
65
@@ -105,11 +109,25 @@ def perform_setup(self, *_args, **_kwargs):
105
109
'qubes-customize' , Gtk .IconSize .LARGE_TOOLBAR )
106
110
settings_image = Gtk .Image .new_from_pixbuf (settings_pixbuf )
107
111
self .button_settings .set_image (settings_image )
112
+
113
+ overriden_restart = None
114
+ if self .cliargs .restart :
115
+ overriden_restart = True
116
+ elif self .cliargs .no_restart :
117
+ overriden_restart = False
118
+
119
+ overrides = OverridenSettings (
120
+ restart = overriden_restart ,
121
+ max_concurrency = self .cliargs .max_concurrency ,
122
+ update_if_stale = self .cliargs .update_if_stale ,
123
+ )
124
+
108
125
self .settings = Settings (
109
126
self .main_window ,
110
127
self .qapp ,
111
128
self .log ,
112
- refresh_callback = self .intro_page .refresh_update_list
129
+ refresh_callback = self .intro_page .refresh_update_list ,
130
+ overrides = overrides ,
113
131
)
114
132
115
133
headers = [(3 , "intro_name" ), (3 , "progress_name" ), (3 , "summary_name" ),
@@ -137,6 +155,23 @@ def cell_data_func(_column, cell, model, it, data):
137
155
self .main_window .connect ("key-press-event" , self .check_escape )
138
156
139
157
self .intro_page .populate_vm_list (self .qapp , self .settings )
158
+
159
+ if skip_intro_if_args (self .cliargs ):
160
+ self .log .info ("Skipping intro page." )
161
+ self .intro_page .select_rows_ignoring_conditions (
162
+ cliargs = self .cliargs )
163
+ if len (self .intro_page .get_vms_to_update ()) == 0 :
164
+ show_dialog_with_icon (
165
+ None , l ("Quit" ),
166
+ l ("Nothing to do." ),
167
+ buttons = RESPONSES_OK ,
168
+ icon_name = "qubes-info"
169
+ )
170
+ self .main_window .close ()
171
+ return
172
+ self .next_clicked (None , skip_intro = True )
173
+ else :
174
+ self .log .info ("Show intro page." )
140
175
self .main_window .show_all ()
141
176
width = self .intro_page .vm_list .get_preferred_width ().natural_width
142
177
self .main_window .resize (width + 50 , int (width * 1.2 ))
@@ -145,9 +180,9 @@ def cell_data_func(_column, cell, model, it, data):
145
180
def open_settings_window (self , _emitter ):
146
181
self .settings .show ()
147
182
148
- def next_clicked (self , _emitter ):
183
+ def next_clicked (self , _emitter , skip_intro = False ):
149
184
self .log .debug ("Next clicked" )
150
- if self .intro_page .is_visible :
185
+ if self .intro_page .is_visible or skip_intro :
151
186
vms_to_update = self .intro_page .get_vms_to_update ()
152
187
self .intro_page .active = False
153
188
self .progress_page .show ()
@@ -213,9 +248,61 @@ def exit_updater(self, _emitter=None):
213
248
self .release ()
214
249
215
250
216
- def main ():
251
+ def parse_args (args ):
252
+ parser = argparse .ArgumentParser ()
253
+
254
+ parser .add_argument ('--log' , action = 'store' , default = 'WARNING' ,
255
+ help = 'Provide logging level. Values: DEBUG, INFO, '
256
+ 'WARNING (default), ERROR, CRITICAL' )
257
+ parser .add_argument ('--max-concurrency' , action = 'store' ,
258
+ help = 'Maximum number of VMs configured simultaneously '
259
+ '(default: number of cpus)' ,
260
+ type = int )
261
+ restart_gr = parser .add_mutually_exclusive_group ()
262
+ restart_gr .add_argument ('--restart' , action = 'store_true' ,
263
+ help = 'Restart AppVMs whose template '
264
+ 'has been updated.' )
265
+ restart_gr .add_argument ('--no-restart' , action = 'store_true' ,
266
+ help = 'Do not restart AppVMs whose template '
267
+ 'has been updated.' )
268
+
269
+ group = parser .add_mutually_exclusive_group ()
270
+ group .add_argument ('--targets' , action = 'store' ,
271
+ help = 'Comma separated list of VMs to target' )
272
+ group .add_argument ('--all' , action = 'store_true' ,
273
+ help = 'Target all non-disposable VMs (TemplateVMs and '
274
+ 'AppVMs)' )
275
+ group .add_argument ('--update-if-stale' , action = 'store' ,
276
+ help = 'Target all TemplateVMs with known updates or for '
277
+ 'which last update check was more than N days '
278
+ 'ago.' ,
279
+ type = int )
280
+
281
+ parser .add_argument ('--skip' , action = 'store' ,
282
+ help = 'Comma separated list of VMs to be skipped, '
283
+ 'works with all other options.' , default = "" )
284
+ parser .add_argument ('--templates' , action = 'store_true' ,
285
+ help = 'Target all TemplatesVMs' )
286
+ parser .add_argument ('--standalones' , action = 'store_true' ,
287
+ help = 'Target all StandaloneVMs' )
288
+ parser .add_argument ('--dom0' , action = 'store_true' ,
289
+ help = 'Target dom0' )
290
+
291
+ args = parser .parse_args (args )
292
+
293
+ return args
294
+
295
+
296
+ def skip_intro_if_args (args ):
297
+ return args is not None and (args .templates or args .standalones or args .skip
298
+ or args .update_if_stale or args .all
299
+ or args .targets or args .dom0 )
300
+
301
+
302
+ def main (args = None ):
303
+ cliargs = parse_args (args )
217
304
qapp = Qubes ()
218
- app = QubesUpdater (qapp )
305
+ app = QubesUpdater (qapp , cliargs )
219
306
app .run ()
220
307
221
308
0 commit comments