#!/usr/bin/env python # # Archey [version 0.3.0] # # Archey is a simple system information tool written in Python. # # Copyright 2010 Melik Manukyan # # ASCII art by Brett Bohnenkamper # Changes Jerome Launay # Fedora support by YeOK # # Distributed under the terms of the GNU General Public License v3. # See http://www.gnu.org/licenses/gpl.txt for the full license text. # Import libraries import os, sys, subprocess, optparse, re, linecache from optparse import OptionParser from getpass import getuser from time import ctime, sleep #---------------Output---------------# output = [ 'User', 'Hostname', 'Distro', 'Kernel', 'Uptime', 'WindowManager', 'DesktopEnvironment', 'Shell', 'Terminal', 'Packages', 'CPU', 'RAM', 'Disk' ] #---------------Dictionaries---------------# class NoDeleteDict(dict): """ This dict silently disables deletions. This is because allthough we will want users to be able to edit these dicts from their config files, we don't want them to muck up somthing important, so we disable deletions to protect them from themselves. >>>dic = NoDeleteDict({'a':1, 'b':2}) We can still access items normally: >>>dic['a'] 1 But when we delete items, nothing happens: >>>del dic['b'] >>>dic['b'] 2 """ def __delitem__(self, name): return COLOR_DICT = NoDeleteDict({ 'Arch Linux': ['\x1b[0;34m', '\x1b[1;34m'], 'Ubuntu': ['\x1b[0;31m', '\x1b[1;31m', '\x1b[0;33m'], 'Debian': ['\x1b[0;31m', '\x1b[1;31m'], 'Mint': ['\x1b[0;32m', '\x1b[1;37m'], 'Crunchbang': ['\x1b[1;37m'], 'Fedora': ['\x1b[0;34m', '\x1b[1;37m'], 'Clear': '\x1b[0m' }) DE_DICT = NoDeleteDict({ 'gnome-session': 'GNOME', 'ksmserver': 'KDE', 'xfce4-session': 'Xfce', 'lxsession': 'LXDE' }) WM_DICT = NoDeleteDict({ 'awesome': 'Awesome', 'beryl': 'Beryl', 'blackbox': 'Blackbox', 'compiz': 'Compiz', 'dwm': 'DWM', 'enlightenment': 'Enlightenment', 'fluxbox': 'Fluxbox', 'fvwm': 'FVWM', 'i3': 'i3', 'icewm': 'IceWM', 'kwin': 'KWin', 'metacity': 'Metacity', 'musca': 'Musca', 'openbox': 'Openbox', 'pekwm': 'PekWM', 'ratpoison': 'ratpoison', 'scrotwm': 'ScrotWM', 'wmaker': 'Window Maker', 'wmfs': 'Wmfs', 'wmii': 'wmii', 'xfwm4': 'Xfwm', 'xmonad': 'xmonad' }) LOGO_DICT = NoDeleteDict({'Arch Linux': '''{color[1]} {color[1]} + {results[0]} {color[1]} # {results[1]} {color[1]} ### {results[2]} {color[1]} ##### {results[3]} {color[1]} ###### {results[4]} {color[1]} ; #####; {results[5]} {color[1]} +##.##### {results[6]} {color[1]} +########## {results[7]} {color[1]} ######{color[0]}#####{color[1]}##; {results[8]} {color[1]} ###{color[0]}############{color[1]}+ {results[9]} {color[1]} #{color[0]}###### ####### {results[10]} {color[0]} .######; ;###;`\". {results[11]} {color[0]} .#######; ;#####. {results[12]} {color[0]} #########. .########` {results[13]} {color[0]} ######' '###### {results[14]} {color[0]} ;#### ####; {results[15]} {color[0]} ##' '## {results[16]} {color[0]} #' `# {results[17]} \x1b[0m'''}) PROCESSES = str(subprocess.check_output(('ps', '-u', getuser(), '-o', 'comm', '--no-headers')), encoding='utf8').rstrip('\n').split('\n') #--------------Exceptions-------------# class ArcheyException(Exception): pass #---------------Classes---------------# class Output(list): results = [] def __init__(self): self.distro = self.__detectDistro() super().__init__() def __detectDistro(self): if os.path.exists('/etc/pacman.conf'): return 'Arch Linux' else: sys.exit("Unsupported distro") def _color(self, index): """ Returns the escape code for either: a) The color scheme of the distro value stored in self.distro or b) The value of the entry in COLOR_DICT for the key passed >>out = Output() >>out._color(1) == COLOR_DICT[out.distro][1] >>out._color(out.distro) == COLOR_DICT[out.distro] """ if isinstance(index, str): return COLOR_DICT[index] return COLOR_DICT[self.distro][index] def _get_logo(self): return LOGO_DICT[self.distro] def _center_results(self, results, max_length=17): """ Centers a list of results. Length of desired list can be given via max_length kwarg. >>>out = Output() >>>out._center_results([1]) [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 1, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '] >>>out._center_results([1], max_length=3) [' ', 1, ' '] """ length = len(results) if length > max_length: return results[:max_length + 1] center = int(max_length/2) start = int(center - length/2) new_results = list(' ' * max_length) new_results[start:start + length - 1] = results return new_results def append(self, display): super().append('%s%s: %s%s' % (self._color(1), display.key, self._color('Clear'), display.value)) def output(self): results = self._center_results(self) print(self._get_logo().format(color=self._color(self.distro), results=results)) class BaseDisplay(): """ All display classes should inherit this. It defigns several base functions that can be overwritten by any child classes >>>import random >>>class RandomNumber(BaseDisplay): ... key = 'Random Number' ... value = random.random() * 1000 ... >>>r = RandomNumber() >>>print `r` """ key = None value = None def __init__(self): raise NotImplemented('Display classes must implements their own __init__ function') def __repr__(self): return '<{0}: key={1}, value={2}>'.format(self.__class__.__name__, self.key, self.value) #class Hostname: # def __init__(self): #class Distro: # def __init__(self): #class Kernel: # def __init__(self): class Uptime(BaseDisplay): def __init__(self): fuptime = int(open('/proc/uptime').read().split('.')[0]) day = int(fuptime / 86400) fuptime = fuptime % 86400 hour = int(fuptime / 3600) fuptime = fuptime % 3600 minute = int(fuptime / 60) uptime = '' if day == 1: uptime += '%d day, ' % day if day > 1: uptime += '%d days, ' % day uptime += '%d:%02d' % (hour, minute) self.key = 'Uptime' self.value = uptime class WindowManager(BaseDisplay): def __init__(self): wm = '' for key in WM_DICT.keys(): if key in PROCESSES: wm = WM_DICT[key] break self.key = 'Window Manager' self.value = wm class DesktopEnvironment(BaseDisplay): def __init__(self): de = '' for key in DE_DICT.keys(): if key in PROCESSES: wm = WM_DICT[key] break self.key = 'Desktop Environment' self.value = de def enviroment_variable(klass): """ Decorate classes with this decorator. Classes decorated with enviroment_variable will have their __init__ function automaticly generated. This makes it very easy to write a class that returns an enviroment variable. >>>@enviroment_variable ...class Lang(): ... key = 'Language' ... env = 'LANG' ... >>>test = Lang() >>>import os >>>assert test.value == os.getenv('LANG') """ def __init__(self): self.value = os.getenv(self.env) if hasattr(klass, 'key') and hasattr(klass, 'env'): klass.__init__ = __init__ else: raise ArcheyException('Classes decorated with @enviroment_variable must have' 'key and env attributes') return klass @enviroment_variable class Shell(BaseDisplay): key = 'Shell' env = 'SHELL' @enviroment_variable class Terminal(BaseDisplay): key = 'Terminal' env = 'TERM' @enviroment_variable class User(BaseDisplay): key = 'User' env = 'USER' #class Packages(): # def __init__(self): #class CPU(): # def __init__(self): #class RAM(): # def __init__(self): #class Disk(): # def __init__(self): ## TEST ## <<< TEMPORARY def main(): out = Output() out.append(Shell()) out.append(User()) out.append(Terminal()) out.append(Uptime()) out.append(WindowManager()) #out.append(DesktopEnvirornment()) out.output() if __name__ == '__main__': main()