summaryrefslogtreecommitdiff
path: root/archey3
diff options
context:
space:
mode:
authorLaurie Clark-Michalek <bluepeppers@archlinux.us>2012-08-10 09:04:09 +0100
committerLaurie Clark-Michalek <bluepeppers@archlinux.us>2012-08-10 09:04:09 +0100
commit4201af9d8597dd4151d9d4335103ae972030a299 (patch)
tree81b0cdb5aad09a731c8641acc6aef2ea94cce118 /archey3
parentf7041ecbebd24ffc1225f07c6eac21d8f9d1c1d2 (diff)
Added cpu module as uname -p no longer works. Fixes #8
Diffstat (limited to 'archey3')
-rw-r--r--archey3177
1 files changed, 94 insertions, 83 deletions
diff --git a/archey3 b/archey3
index 4684880..226c08d 100644
--- a/archey3
+++ b/archey3
@@ -3,11 +3,11 @@
# archey3 [version 0.4]
#
# Copyright 2010 Melik Manukyan <melik@archlinux.us>
-# Copyright 2010-2011 Laurie Clark-Michalek <bluepeppers@archlinux.us>
+# Copyright 2010-2012 Laurie Clark-Michalek <bluepeppers@archlinux.us>
# Distributed under the terms of the GNU General Public License v3.
# See http://www.gnu.org/licenses/gpl.txt for the full license text.
#
-# Simple python script to display an Archlinux logo in ASCII art
+# Simple python script to display an Archlinux logo in ASCII art
# Along with basic system information.
# Import libraries
@@ -31,7 +31,7 @@ except ImportError:
self.level = level
debug = info = warn = warning = notice = error = exception = \
critical = log = lambda *a, **kw: None
-
+
def lookup_level(_):
return 0
@@ -63,7 +63,7 @@ LOGOS = {'Arch Linux': '''{c1}
{c2} #########. .########` {results[13]}
{c2} ######' '###### {results[14]}
{c2} ;#### ####; {results[15]}
-{c2} ##' '## {results[16]}
+{c2} ##' '## {results[16]}
{c2} #' `# {results[17]}
\x1b[0m'''
}
@@ -85,7 +85,7 @@ DE_DICT = {'gnome-session': 'GNOME',
'lxsession': 'LXDE',
'': 'None',
}
-
+
WM_DICT = {
'awesome': 'Awesome',
'beryl': 'Beryl',
@@ -136,12 +136,12 @@ State = collections.namedtuple("State", "color config logger")
class display(object):
command_line = ''
stdindata = ''
-
+
def __init__(self, state, args=()):
self.state = state
# Python3 unpacking is awesome
self.arg1, self.arg2, self.arg3, *_ = tuple(args) + ('', '', '')
-
+
@staticmethod
def call_command(command):
"""
@@ -151,7 +151,7 @@ class display(object):
proc = Popen(command.split(), stdout=PIPE)
proc.wait()
return proc.communicate()[0].decode()
-
+
def run_command(self):
if self.command_line:
if '{arg3}' in self.command_line:
@@ -163,36 +163,36 @@ class display(object):
cmd = self.command_line.format(arg1=self.arg1)
else:
cmd = self.command_line
-
+
try:
self.process = Popen(cmd.split(), stdin=PIPE, stdout=PIPE,
stderr=PIPE)
except Exception as e:
self.state.logger.error("Could not run command {0}".format(cmd))
-
+
def render(self):
(stdoutdata, stderrdata) = self.process.communicate(self.stdindata
or None)
-
+
return self.format_output(stdoutdata.decode())
-
+
def color_me(self, output, number=None, low=30, low_color='green',
medium=60, medium_color='yellow', high_color='red'):
if number is None and output.isdigit():
number = int(output)
elif number is None:
return output
-
+
if number <= low:
color_= low_color
elif low < number <= medium:
color_ = medium_color
elif medium < number:
color_ = high_color
-
+
return '{0}{1}{2}'.format(color(self.state, color_), output,
color(self.state, 'clear'))
-
+
regex_class = re.compile("").__class__
def process_exists(self, key):
global PROCESSES
@@ -206,7 +206,7 @@ class display(object):
@module_register("fs")
class fsDisplay(display):
command_line = "df -TPh {arg1}"
-
+
conversions = {
'binary': {
'K': 2 ** 10,
@@ -221,14 +221,14 @@ class fsDisplay(display):
'T': 10 ** 12,
},
}
-
+
def __init__(self, **kwargs):
super().__init__(**kwargs)
if not self.arg1:
msg = "Did not any arguments, require one, the fs to display"
self.state.logger.error(msg)
raise ArgumentError(self, msg)
-
+
def format_output(self, instring):
try:
decimal_point = self.call_command(
@@ -243,13 +243,13 @@ class fsDisplay(display):
fstype = values[1]
conversion_type = self.state.config.get('fs', 'unit', fallback="si").lower()
conversions = self.conversions[conversion_type]
-
- mount = '/root' if self.arg1 == '/' else self.arg1
+
+ mount = '/root' if self.arg1 == '/' else self.arg1
title = mount.split('/')[-1].title()
-
+
low = self.state.config.getint('fs', 'low_bound', fallback=40)
medium = self.state.config.getint('fs', 'medium_bound', fallback=70)
-
+
try:
#convert to straight float
used_ = float(used[:-1]) * conversions[used[-1].upper()]
@@ -261,7 +261,7 @@ class fsDisplay(display):
return
else:
used = self.color_me(used, persentage, low=low, medium=medium)
-
+
if self.state.config.getboolean("fs", "persentage", fallback=True):
part = '{used} / {total} ({persentage}%) ({fstype})'.format(
used=used, total=total, persentage=int(persentage),
@@ -274,7 +274,7 @@ class fsDisplay(display):
@module_register("ram")
class ramDisplay(display):
command_line = "free -m"
-
+
def format_output(self, instring):
ram = ''.join(line for line in str(instring).split('\n') if\
line.startswith('Mem:')).split()
@@ -289,11 +289,11 @@ class ramDisplay(display):
used = self.color_me(number=persentage, output=str(used) + ' MB')
part = '{used} / {total} MB'.format(used=used, total=total)
return title, part
-
+
@module_register("sensor")
class sensorDisplay(display):
command_line = "sensors {arg1}"
-
+
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -305,15 +305,15 @@ class sensorDisplay(display):
self.state.logger.error(
"Did not get any arguments, require one, the sensor to display.")
raise
-
+
if arg_from_arg:
self.arg1 = arg_from_arg
else:
self.arg1 = arg_from_conf
-
+
def format_output(self, instring):
tempinfo = instring.split('\n')[2::4]
-
+
out = []
for line in tempinfo:
info = [re.sub("\s\s+", "", line) for line in line.split(' ') if\
@@ -341,9 +341,9 @@ class envDisplay(display):
self.state.logger.error("Did not get any arguments, require one," +
" the env variable to display.")
raise
-
+
super().__init__(**kwargs)
-
+
def render(self):
argvalue = getenv(self.arg1.upper())
return ('$' + self.arg1.upper(), argvalue)
@@ -351,17 +351,17 @@ class envDisplay(display):
@module_register("uname")
class unameDisplay(display):
command_line = "uname {arg1}"
-
+
def __init__(self, **kwargs):
super().__init__(**kwargs)
-
+
try:
flag = kwargs["args"][0]
except IndexError:
self.state.logger.error("Did not get any arguments, require one," +
" the flag to pass to uname")
raise
-
+
arg_from_conf = self.state.config.get('uname', 'argument', fallback="")
arg_from_arg = flag
if arg_from_arg:
@@ -370,17 +370,28 @@ class unameDisplay(display):
self.arg1 = '-' + arg_from_conf
else:
self.arg1 = ''
-
+
def format_output(self, instring):
return (UNAME_FLAG_MEANINGS[self.arg1[1]], instring)
+@module_register("cpu")
+class cpuDisplay(display):
+ command_line = "cat /proc/cpuinfo"
+
+ def format_output(self, instring):
+ kv = [line.split(":") for line in instring.split("\n") if line]
+ infodict = {}
+ for k, v in kv:
+ infodict[k.strip()] = v.strip()
+ return "Processor Type", infodict["model name"]
+
@module_register("uptime")
class uptimeDisplay(display):
def render(self):
with open("/proc/uptime") as upfile:
raw = upfile.read()
fuptime = int(raw.split('.')[0])
-
+
day = int(fuptime / 86400)
fuptime = fuptime % 86400
hour = int(fuptime / 3600)
@@ -396,7 +407,7 @@ class uptimeDisplay(display):
@module_register("packages")
class packageDisplay(display):
command_line = "pacman -Q"
-
+
def format_output(self, instring):
return "Packages", len(instring.split('\n'))
@@ -415,26 +426,26 @@ class distroCheck(display):
@module_register("process")
class processCheck(display):
command_line = "ps -u " + getuser()
-
+
render = lambda self: self
-
+
def run_command(self):
super().run_command()
out = str(self.process.communicate()[0])
-
+
self._processes = set()
for line in out.split("\\n"):
words = line.split()
if len(words) <= 3:
continue
-
+
self._processes.add(words[3])
-
+
def __call__(self, proc):
if proc in self._processes:
return True
return False
-
+
@module_register("wm")
class wmDisplay(display):
def render(self):
@@ -466,10 +477,10 @@ class mpdDisplay(display):
nothing.
"""
command_line = "mpc stats --host {arg1} --port {arg2}"
-
+
def __init__(self, **kwargs):
super().__init__(**kwargs)
-
+
try:
self.stat = kwargs["args"][0]
except IndexError:
@@ -477,7 +488,7 @@ class mpdDisplay(display):
" the stat to display.")
self.arg1 = self.state.config.get('mpd', 'host', fallback='localhost')
self.arg2 = self.state.config.getint('mpd', 'port', fallback=6600)
-
+
def format_output(self, instring):
lines = instring.split('\n')
stats = {}
@@ -490,7 +501,7 @@ class mpdDisplay(display):
self.state.logger.error(
"Could not parse mpc output, is mpc installed?")
return
-
+
return ('{statname} in MPD database'.format(statname=self.stat.title()),
stats[self.stat])
@@ -506,10 +517,10 @@ class ArcheyConfigParser(configparser.SafeConfigParser):
'display_modules':
"""\
distro(), uname(n), uname(r), uptime(), wm(), de(), packages(), ram(),\
- uname(p), env(editor), fs(/), mpd(albums)"""
+ cpu(), env(editor), fs(/), mpd(albums)"""
},
}
-
+
def read(self, file_location=None):
"""
Loads the config options stored in at file_location. If file_location
@@ -517,12 +528,12 @@ distro(), uname(n), uname(r), uptime(), wm(), de(), packages(), ram(),\
($XDG_CONFIG_HOME/archey3.cfg). If that does not exist, it will write a
default config file to $XDG_CONFIG_HOME/archey3.cfg.
"""
-
+
config_location = os.path.expandvars(os.path.expanduser(
file_location or "$XDG_CONFIG_HOME/archey3.cfg"))
-
+
loaded = super(ArcheyConfigParser, self).read(config_location)
-
+
if file_location == None and not loaded:
self.load_default_config()
self.write_config(config_location)
@@ -539,7 +550,7 @@ distro(), uname(n), uname(r), uptime(), wm(), de(), packages(), ram(),\
for section, values in self.defaults.items():
if not self.has_section(section):
self.add_section(section)
-
+
for option, value in values.items():
#strip any excess spaces
value = re.sub("( +)", " ", value)
@@ -551,7 +562,7 @@ distro(), uname(n), uname(r), uptime(), wm(), de(), packages(), ram(),\
"""
with open(location, 'w') as configfile:
self.write(configfile)
-
+
#------------ Functions -----------
@@ -566,11 +577,11 @@ def screenshot(state):
print('.', end='')
sys.stdout.flush()
sleep(1.0/3)
-
+
print('Say Cheese!')
sys.stdout.flush()
-
- screenshot_command = state.config.get('core', 'screenshot_command',
+
+ screenshot_command = state.config.get('core', 'screenshot_command',
fallback="import -window root <datetime>.jpg")
try:
subprocess.check_call(
@@ -618,7 +629,7 @@ def render_class(state, cls, args):
logger=Logger(cls.__name__, state.logger.level),
color=state.color,
config=state.config))
-
+
except Exception as e:
state.logger.error(
"Could not instantiate {0}, failed with error {1}".format(
@@ -636,50 +647,50 @@ def render_class(state, cls, args):
class Archey(object):
DISPLAY_PARSING_REGEX = "(?P<func>\w+)\((|(?P<args>[\w, /]+))\)"
-
+
def __init__(self, config, options):
log_level = lookup_level(options.log_level)
logger = Logger("Core", log_level)
-
+
self.display = config.get("core", "display_modules")
colorscheme = options.color or config.get(
"core", "color", fallback="blue")
for key in COLORS.keys():
if key == colorscheme:
colorcode = COLORS[key]
-
+
self.state = State(colorcode, config, logger)
-
+
global PROCESSES
PROCESSES = render_class(self.state, processCheck, ())
-
+
distro_out = render_class(self.state, distroCheck, ())
-
+
if not distro_out:
self.state.logger.critical(
"Unrecognised distribution.")
raise RuntimeException("Unrecognised distribution.")
-
+
self.distro_name = ' '.join(distro_out[1].split()[:-1])
-
+
def run(self, screenshot_=False):
"""
Actually print the logo etc, and take a screenshot if required.
"""
print(self.render())
-
+
if screenshot_:
screenshot(self.state)
-
+
def render(self):
results = self.prepare_results()
results = self.arrange_results(results)
-
+
return LOGOS[self.distro_name].format(c1=color(self.state, 1),
c2=color(self.state, 2),
results = results
)
-
+
def prepare_results(self):
"""
Renders all classes found in the display array, and then returns them
@@ -687,9 +698,9 @@ class Archey(object):
left over spaces being filled with empty strings.
"""
poolsize = self.state.config.getint("core", "poolsize", fallback=5)
-
+
pool = multiprocessing.Pool(poolsize)
-
+
arguments = []
for cls_name, args in self.parse_display():
arguments.append({
@@ -700,10 +711,10 @@ class Archey(object):
raw_out = pool.map(_mp_render_helper, arguments)
outputs = list(map(self.format_item,
filter(bool, raw_out)))
-
-
+
+
return outputs + [""] * (18 - len(outputs))
-
+
def arrange_results(self, results):
"""
Arranges the results as specified in the config file.
@@ -721,7 +732,7 @@ class Archey(object):
[""] * (len(results) - len(actuall_res)))
else:
return results
-
+
def parse_display(self):
"""
Iterates over the display attribute of the Archey class, and tries to
@@ -729,26 +740,26 @@ class Archey(object):
"""
for func in self.display.split(","):
func = func.strip()
-
+
info = re.match(self.DISPLAY_PARSING_REGEX, func)
if not info:
self.state.logger.error(
"Could not parse display string {0}".format(func))
continue
-
+
groups = info.groupdict()
if groups["args"]:
args = [arg.strip() for arg in groups["args"].split(",")]
else:
args = ()
-
+
yield groups["func"], args
raise StopIteration
def format_item(self, item):
title = item[0].rstrip(':')
data = str(item[1]).rstrip()
-
+
#if we're dealing with a fraction
if len(data.split('/')) == 2:
numerator = data.split('/')[0]
@@ -756,7 +767,7 @@ class Archey(object):
color(self.state, 'clear'))
denominator = data.split('/')[1]
data = '/'.join((numerator, denominator))
-
+
return "{color}{title}:{clear} {data}".format(
color=color(self.state, 1),
title=title,
@@ -799,10 +810,10 @@ def main():
help="The level of errors you wish to display. Choices are\
NOTSET, DEBUG, INFO, WARNING, ERROR, and CRITICAL. CRITICAL is the default.")
(options, args) = parser.parse_args()
-
+
config = ArcheyConfigParser()
config.read(options.config)
-
+
archey = Archey(config=config, options=options)
archey.run(options.screenshot)