2323# imports
2424import sys
2525import os
26+ import shutil
2627import subprocess
2728import platform
2829from re import match , I
2930from clint .textui import colored , prompt
31+ import adafruit_platformdetect
3032
3133__version__ = "0.0.0-auto.0"
3234__repo__ = "https://github.com/adafruit/Adafruit_Python_Shell.git"
3335
34-
36+ # pylint: disable=too-many-public-methods
3537class Shell :
3638 """
3739 Class to help with converting Shell scripts over to Python. Having all
@@ -50,7 +52,11 @@ def select_n(message, selections):
5052
5153 for index , selection in enumerate (selections ):
5254 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+ }
5460 )
5561 return prompt .options (message , options )
5662
@@ -105,11 +111,20 @@ def error(self, message):
105111 print (message )
106112
107113 @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 ):
109122 """
110123 A Yes/No prompt that accepts optional defaults
111124 Returns True for Yes and False for No
112125 """
126+ if force_arg is not None and self .argument_exists (force_arg ):
127+ return True
113128 if default is None :
114129 choicebox = "[y/n]"
115130 else :
@@ -157,24 +172,80 @@ def chdir(self, directory):
157172 directory = self .getcwd () + "/" + directory
158173 return os .chdir (directory )
159174
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+
160189 @staticmethod
161190 def is_root ():
162191 """
163192 Return whether the current user is logged in as root or has super user access
164193 """
165194 return os .geteuid () == 0
166195
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+
167239 def require_root (self ):
168240 """
169241 Check if the current user has root access and exit if not.
170242 """
171243 if not self .is_root ():
172244 print ("Installer must be run as root." )
173- print ("Try 'sudo python3 {}'" .format (sys . argv [ 0 ] ))
245+ print ("Try 'sudo python3 {}'" .format (self . script () ))
174246 sys .exit (1 )
175247
176- @staticmethod
177- def write_text_file (path , content , append = True ):
248+ def write_text_file (self , path , content , append = True ):
178249 """
179250 Write the contents to a file at the specified path
180251 """
@@ -183,7 +254,7 @@ def write_text_file(path, content, append=True):
183254 content = "\n " + content
184255 else :
185256 mode = "w"
186- service_file = open (path , mode )
257+ service_file = open (self . path ( path ) , mode )
187258 service_file .write (content )
188259 service_file .close ()
189260
@@ -192,7 +263,115 @@ def is_linux():
192263 """
193264 Check that we are running linux
194265 """
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 ()
196375
197376 @staticmethod
198377 def kernel_minimum (version ):
0 commit comments