23
23
# imports
24
24
import sys
25
25
import os
26
+ import shutil
26
27
import subprocess
27
28
import platform
28
29
from re import match , I
29
30
from clint .textui import colored , prompt
31
+ import adafruit_platformdetect
30
32
31
33
__version__ = "0.0.0-auto.0"
32
34
__repo__ = "https://github.com/adafruit/Adafruit_Python_Shell.git"
33
35
34
-
36
+ # pylint: disable=too-many-public-methods
35
37
class Shell :
36
38
"""
37
39
Class to help with converting Shell scripts over to Python. Having all
@@ -50,7 +52,11 @@ def select_n(message, selections):
50
52
51
53
for index , selection in enumerate (selections ):
52
54
options .append (
53
- {"selector" : str (index + 1 ), "prompt" : selection , "return" : index + 1 ,}
55
+ {
56
+ "selector" : str (index + 1 ),
57
+ "prompt" : selection ,
58
+ "return" : index + 1 ,
59
+ }
54
60
)
55
61
return prompt .options (message , options )
56
62
@@ -105,11 +111,20 @@ def error(self, message):
105
111
print (message )
106
112
107
113
@staticmethod
108
- def prompt (message , default = None ):
114
+ def print_colored (message , color ):
115
+ """Print out a message in a specific color"""
116
+ colors = ("red" , "green" , "yellow" , "blue" , "black" , "magenta" , "cyan" , "white" )
117
+ if color in colors :
118
+ colorize = getattr (colored , color )
119
+ print (colorize (message ))
120
+
121
+ def prompt (self , message , * , default = None , force_arg = None ):
109
122
"""
110
123
A Yes/No prompt that accepts optional defaults
111
124
Returns True for Yes and False for No
112
125
"""
126
+ if force_arg is not None and self .argument_exists (force_arg ):
127
+ return True
113
128
if default is None :
114
129
choicebox = "[y/n]"
115
130
else :
@@ -157,24 +172,80 @@ def chdir(self, directory):
157
172
directory = self .getcwd () + "/" + directory
158
173
return os .chdir (directory )
159
174
175
+ @staticmethod
176
+ def path (file_path ):
177
+ """
178
+ Return the relative path. This works for paths starting with ~
179
+ """
180
+ return os .path .expanduser (file_path )
181
+
182
+ @staticmethod
183
+ def home_dir ():
184
+ """
185
+ Return the User's home directory
186
+ """
187
+ return os .path .expanduser ("~" )
188
+
160
189
@staticmethod
161
190
def is_root ():
162
191
"""
163
192
Return whether the current user is logged in as root or has super user access
164
193
"""
165
194
return os .geteuid () == 0
166
195
196
+ @staticmethod
197
+ def script ():
198
+ """
199
+ Return the name of the script that is running
200
+ """
201
+ return sys .argv [0 ]
202
+
203
+ def grep (self , search_term , location ):
204
+ """
205
+ Run the grep command and return the result
206
+ """
207
+ location = self .path (location )
208
+ return self .run_command (
209
+ "grep {} {}" .format (search_term , location ), suppress_message = True
210
+ )
211
+
212
+ def exists (self , location ):
213
+ """
214
+ Check if a path or file exists
215
+ """
216
+ location = self .path (location )
217
+ return os .path .exists (location )
218
+
219
+ def move (self , source , destination ):
220
+ """
221
+ Move a file or directory from source to destination
222
+ """
223
+ source = self .path (source )
224
+ destination = self .path (destination )
225
+ if os .path .exists (source ):
226
+ shutil .move (source , destination )
227
+
228
+ def remove (self , location ):
229
+ """
230
+ Remove a file or directory if it exists
231
+ """
232
+ location = self .path (location )
233
+ if os .path .exists (location ):
234
+ if os .path .isdir (location ):
235
+ shutil .rmtree (location )
236
+ else :
237
+ os .remove (location )
238
+
167
239
def require_root (self ):
168
240
"""
169
241
Check if the current user has root access and exit if not.
170
242
"""
171
243
if not self .is_root ():
172
244
print ("Installer must be run as root." )
173
- print ("Try 'sudo python3 {}'" .format (sys . argv [ 0 ] ))
245
+ print ("Try 'sudo python3 {}'" .format (self . script () ))
174
246
sys .exit (1 )
175
247
176
- @staticmethod
177
- def write_text_file (path , content , append = True ):
248
+ def write_text_file (self , path , content , append = True ):
178
249
"""
179
250
Write the contents to a file at the specified path
180
251
"""
@@ -183,7 +254,7 @@ def write_text_file(path, content, append=True):
183
254
content = "\n " + content
184
255
else :
185
256
mode = "w"
186
- service_file = open (path , mode )
257
+ service_file = open (self . path ( path ) , mode )
187
258
service_file .write (content )
188
259
service_file .close ()
189
260
@@ -192,7 +263,115 @@ def is_linux():
192
263
"""
193
264
Check that we are running linux
194
265
"""
195
- return platform .system () == "Linux"
266
+ return platform .system () == "Linux" or platform .system () == "Darwin"
267
+
268
+ @staticmethod
269
+ def is_armhf ():
270
+ """
271
+ Check if Platform.machine() (same as uname -m) returns an ARM platform that
272
+ supports hardware floating point
273
+ """
274
+ return bool (match ("armv.l" , platform .machine ()))
275
+
276
+ @staticmethod
277
+ def is_armv6 ():
278
+ """
279
+ Check if Platform.machine() returns ARM v6
280
+ """
281
+ return platform .machine () == "armv6l"
282
+
283
+ @staticmethod
284
+ def is_armv7 ():
285
+ """
286
+ Check if Platform.machine() returns ARM v7
287
+ """
288
+ return platform .machine () == "armv7l"
289
+
290
+ @staticmethod
291
+ def is_armv8 ():
292
+ """
293
+ Check if Platform.machine() returns ARM v8
294
+ """
295
+ return platform .machine () == "armv8l"
296
+
297
+ @staticmethod
298
+ def get_arch ():
299
+ """Return a string containing the architecture"""
300
+ return platform .machine ()
301
+
302
+ # pylint: disable=invalid-name
303
+ def get_os (self ):
304
+ """Return a string containing the release which we can use to compare in the script"""
305
+ os_releases = (
306
+ "Raspbian" ,
307
+ "Debian" ,
308
+ "Kano" ,
309
+ "Mate" ,
310
+ "PiTop" ,
311
+ "Ubuntu" ,
312
+ "Darwin" ,
313
+ "Kali" ,
314
+ )
315
+ release = None
316
+ if os .path .exists ("/etc/os-release" ):
317
+ with open ("/etc/os-release" ) as f :
318
+ if "Raspbian" in f .read ():
319
+ release = "Raspian"
320
+ if self .run_command ("command -v apt-get" , suppress_message = True ):
321
+ with open ("/etc/os-release" ) as f :
322
+ release_file = f .read ()
323
+ for opsys in os_releases :
324
+ if opsys in release_file :
325
+ release = opsys
326
+ if os .path .isdir (os .path .expanduser ("~/.kano-settings" )) or os .path .isdir (
327
+ os .path .expanduser ("~/.kanoprofile" )
328
+ ):
329
+ release = "Kano"
330
+ if os .path .isdir (os .path .expanduser ("~/.config/ubuntu-mate" )):
331
+ release = "Mate"
332
+ if platform .system () == "Darwin" :
333
+ release = "Darwin"
334
+ return release
335
+
336
+ def get_raspbian_version (self ):
337
+ """Return a string containing the raspbian version"""
338
+ if self .get_os () != "Raspbian" :
339
+ return None
340
+ raspbian_releases = ("buster" , "stretch" , "jessie" , "wheezy" )
341
+ if os .path .exists ("/etc/os-release" ):
342
+ with open ("/etc/os-release" ) as f :
343
+ release_file = f .read ()
344
+ if "/sid" in release_file :
345
+ return "unstable"
346
+ for raspbian in raspbian_releases :
347
+ if raspbian in release_file :
348
+ return raspbian
349
+ return None
350
+
351
+ # pylint: enable=invalid-name
352
+
353
+ @staticmethod
354
+ def is_raspberry_pi ():
355
+ """
356
+ Use PlatformDetect to check if this is a Raspberry Pi
357
+ """
358
+ detector = adafruit_platformdetect .Detector ()
359
+ return detector .board .any_raspberry_pi
360
+
361
+ @staticmethod
362
+ def get_board_model ():
363
+ """
364
+ Use PlatformDetect to get the board model
365
+ """
366
+ detector = adafruit_platformdetect .Detector ()
367
+ return detector .board .id
368
+
369
+ @staticmethod
370
+ def get_architecture ():
371
+ """
372
+ Get the type of Processor
373
+ """
374
+ return platform .machine ()
196
375
197
376
@staticmethod
198
377
def kernel_minimum (version ):
0 commit comments