23
23
# imports
24
24
import sys
25
25
import os
26
+ import stat
26
27
import shutil
27
28
import subprocess
28
29
import fcntl
50
51
51
52
WINDOW_MANAGERS = {
52
53
"x11" : "W1" ,
53
- "wayland " : "W2" ,
54
+ "wayfire " : "W2" ,
54
55
"labwc" : "W3" ,
55
56
}
56
57
58
+ FILE_MODES = {
59
+ "+x" : stat .S_IXUSR | stat .S_IXGRP | stat .S_IXOTH ,
60
+ "+r" : stat .S_IRUSR | stat .S_IRGRP | stat .S_IROTH ,
61
+ "+w" : stat .S_IWUSR | stat .S_IWGRP | stat .S_IWOTH ,
62
+ "a+x" : stat .S_IXUSR | stat .S_IXGRP | stat .S_IXOTH ,
63
+ "a+r" : stat .S_IRUSR | stat .S_IRGRP | stat .S_IROTH ,
64
+ "a+w" : stat .S_IWUSR | stat .S_IWGRP | stat .S_IWOTH ,
65
+ "u+x" : stat .S_IXUSR ,
66
+ "u+r" : stat .S_IRUSR ,
67
+ "u+w" : stat .S_IWUSR ,
68
+ "g+x" : stat .S_IXGRP ,
69
+ "g+r" : stat .S_IRGRP ,
70
+ "g+w" : stat .S_IWGRP ,
71
+ "o+x" : stat .S_IXOTH ,
72
+ "o+r" : stat .S_IROTH ,
73
+ "o+w" : stat .S_IWOTH ,
74
+ }
75
+
57
76
58
77
# pylint: disable=too-many-public-methods
59
78
class Shell :
@@ -142,6 +161,50 @@ def preexec():
142
161
return False
143
162
return True
144
163
164
+ def write_templated_file (self , output_path , template , ** kwargs ):
165
+ """
166
+ Use a template file and render it with the given context and write it to the specified path.
167
+ The template file should contain placeholders in the format {key} which will be replaced
168
+ with the corresponding values from the kwargs dictionary.
169
+ """
170
+ # if path is an existing directory, the template filename will be used
171
+ output_path = self .path (output_path )
172
+ if os .path .isdir (output_path ):
173
+ output_path = os .path .join (output_path , os .path .basename (template ))
174
+
175
+ # Render the template with the provided context
176
+ rendered_content = self .load_template (template , ** kwargs )
177
+
178
+ if rendered_content is None :
179
+ self .error (
180
+ f"Failed to load template '{ template } '. Unable to write file '{ output_path } '."
181
+ )
182
+ return False
183
+
184
+ append = kwargs .get ("append" , False )
185
+ self .write_text_file (output_path , rendered_content , append = append )
186
+
187
+ return True
188
+
189
+ def load_template (self , template , ** kwargs ):
190
+ """
191
+ Load a template file and return its content with the placeholders replaced by the provided
192
+ context. The template file should contain placeholders in the format {key} which will be
193
+ replaced with the corresponding values from the kwargs dictionary.
194
+ """
195
+ if not os .path .exists (template ):
196
+ self .error (f"Template file '{ template } ' does not exist" )
197
+ return None
198
+
199
+ with open (template , "r" ) as template_file :
200
+ template_content = template_file .read ()
201
+
202
+ # Render the template with the provided context
203
+ for key , value in kwargs .items ():
204
+ template_content = template_content .replace (f"{{{ key } }}" , str (value ))
205
+
206
+ return template_content
207
+
145
208
def info (self , message , ** kwargs ):
146
209
"""
147
210
Display a message with the group in green
@@ -321,7 +384,10 @@ def reconfig(self, file, pattern, replacement):
321
384
# Not found; append (silently)
322
385
self .write_text_file (file , replacement , append = True )
323
386
324
- def pattern_search (self , location , pattern , multi_line = False , return_match = False ):
387
+ # pylint: disable=too-many-arguments
388
+ def pattern_search (
389
+ self , location , pattern , multi_line = False , return_match = False , find_all = False
390
+ ):
325
391
"""
326
392
Similar to grep, but uses pure python
327
393
multi_line will search the entire file as a large text glob,
@@ -331,16 +397,17 @@ def pattern_search(self, location, pattern, multi_line=False, return_match=False
331
397
"""
332
398
location = self .path (location )
333
399
found = False
400
+ search_function = re .findall if find_all else re .search
334
401
335
402
if self .exists (location ) and not self .isdir (location ):
336
403
if multi_line :
337
404
with open (location , "r+" , encoding = "utf-8" ) as file :
338
- match = re . search (pattern , file .read (), flags = re .DOTALL )
405
+ match = search_function (pattern , file .read (), flags = re .DOTALL )
339
406
if match :
340
407
found = True
341
408
else :
342
409
for line in fileinput .FileInput (location ):
343
- match = re . search (pattern , line )
410
+ match = search_function (pattern , line )
344
411
if match :
345
412
found = True
346
413
break
@@ -417,8 +484,13 @@ def chmod(self, location, mode):
417
484
Change the permissions of a file or directory
418
485
"""
419
486
location = self .path (location )
487
+ # Convert a text mode to an integer mode
488
+ if isinstance (mode , str ):
489
+ if mode not in FILE_MODES :
490
+ raise ValueError (f"Invalid mode string '{ mode } '" )
491
+ mode = FILE_MODES [mode ]
420
492
if not 0 <= mode <= 0o777 :
421
- raise ValueError ("Invalid mode value" )
493
+ raise ValueError (f "Invalid mode value ' { mode } ' " )
422
494
if os .path .exists (location ):
423
495
os .chmod (location , mode )
424
496
@@ -475,6 +547,16 @@ def write_text_file(self, path, content, append=True):
475
547
with open (self .path (path ), mode , encoding = "utf-8" ) as service_file :
476
548
service_file .write (content )
477
549
550
+ def read_text_file (self , path ):
551
+ """
552
+ Read the contents of a file at the specified path
553
+ """
554
+ path = self .path (path )
555
+ if not os .path .exists (path ):
556
+ raise FileNotFoundError (f"File '{ path } ' does not exist" )
557
+ with open (path , "r" , encoding = "utf-8" ) as file :
558
+ return file .read ()
559
+
478
560
@staticmethod
479
561
def is_python3 ():
480
562
"Check if we are running Python 3 or later"
@@ -656,6 +738,29 @@ def set_window_manager(self, manager):
656
738
):
657
739
raise RuntimeError ("Unable to change window manager" )
658
740
741
+ def get_window_manager (self ):
742
+ """
743
+ Get the current window manager
744
+ """
745
+ sessions = {"wayfire" : "LXDE-pi-wayfire" }
746
+ # Check for Raspbian Desktop sessions
747
+ if self .exists ("/usr/share/xsessions/rpd-x.desktop" ) or self .exists (
748
+ "/usr/share/wayland-sessions/rpd-labwc.desktop"
749
+ ):
750
+ sessions .update ({"x11" : "rpd-x" , "labwc" : "rpd-labwc" })
751
+ else :
752
+ sessions .update ({"x11" : "LXDE-pi-x" , "labwc" : "LXDE-pi-labwc" })
753
+
754
+ matches = self .pattern_search (
755
+ "/etc/lightdm/lightdm.conf" , "^(?!#.*?)user-session=(.+)" , False , True
756
+ )
757
+ if matches :
758
+ session_match = matches .group (1 )
759
+ for key , session in sessions .items ():
760
+ if session_match == session :
761
+ return key
762
+ return None
763
+
659
764
def get_boot_config (self ):
660
765
"""
661
766
Get the location of the boot config file
0 commit comments