2020-05-01 20:15:39 +02:00
import os
2020-05-02 13:57:13 +02:00
import ast
2020-05-02 13:43:17 +02:00
from configparser import RawConfigParser
2020-05-01 20:15:39 +02:00
import sys
import glob
import textwrap
2020-01-19 15:36:52 +01:00
import argparse
2020-04-08 11:50:00 +02:00
import logging
2020-01-19 15:36:52 +01:00
2020-05-01 20:15:39 +02:00
import core . theme
2020-01-25 14:24:21 +01:00
import util . store
2020-04-02 16:54:57 +02:00
import util . format
2020-01-25 14:24:21 +01:00
2020-05-01 20:15:39 +02:00
import modules . core
import modules . contrib
2020-04-08 11:50:00 +02:00
log = logging . getLogger ( __name__ )
2020-05-03 11:15:52 +02:00
MODULE_HELP = " Specify a space-separated list of modules to load. The order of the list determines their order in the i3bar (from left to right). Use <module>:<alias> to provide an alias in case you want to load the same module multiple times, but specify different parameters. "
PARAMETER_HELP = (
" Provide configuration parameters in the form of <module>.<key>=<value> "
)
THEME_HELP = " Specify the theme to use for drawing modules "
2020-01-19 15:36:52 +01:00
2020-05-01 20:15:39 +02:00
def all_modules ( ) :
2020-05-10 13:25:13 +02:00
""" Returns a list of all available modules (either core or contrib)
: return : list of modules
: rtype : list of strings
"""
2020-05-01 20:15:39 +02:00
result = { }
2020-05-03 11:15:52 +02:00
for path in [ modules . core . __file__ , modules . contrib . __file__ ] :
2020-05-01 20:15:39 +02:00
path = os . path . dirname ( path )
2020-05-03 11:15:52 +02:00
for mod in glob . iglob ( " {} /*.py " . format ( path ) ) :
result [ os . path . basename ( mod ) . replace ( " .py " , " " ) ] = 1
2020-05-01 20:15:39 +02:00
res = list ( result . keys ( ) )
res . sort ( )
return res
2020-05-03 11:15:52 +02:00
2020-05-01 20:15:39 +02:00
class print_usage ( argparse . Action ) :
def __init__ ( self , option_strings , dest , nargs = None , * * kwargs ) :
argparse . Action . __init__ ( self , option_strings , dest , nargs , * * kwargs )
2020-05-03 11:15:52 +02:00
self . _indent = " " * 2
2020-05-01 20:15:39 +02:00
def __call__ ( self , parser , namespace , value , option_string = None ) :
2020-05-03 11:15:52 +02:00
if value == " modules " :
2020-05-01 20:15:39 +02:00
self . _args = namespace
2020-05-03 11:15:52 +02:00
self . _format = " plain "
2020-05-01 20:15:39 +02:00
self . print_modules ( )
2020-05-05 20:33:27 +02:00
elif value == " modules-rst " :
2020-05-01 20:15:39 +02:00
self . _args = namespace
2020-05-05 20:33:27 +02:00
self . _format = " rst "
2020-05-01 20:15:39 +02:00
self . print_modules ( )
2020-05-03 11:15:52 +02:00
elif value == " themes " :
2020-05-01 20:15:39 +02:00
self . print_themes ( )
sys . exit ( 0 )
def print_themes ( self ) :
2020-05-03 11:15:52 +02:00
print ( " , " . join ( core . theme . themes ( ) ) )
2020-05-01 20:15:39 +02:00
def print_modules ( self ) :
2020-05-03 16:56:23 +02:00
basepath = os . path . abspath (
os . path . join ( os . path . dirname ( os . path . realpath ( __file__ ) ) , " .. " )
)
2020-05-05 20:33:27 +02:00
2020-05-05 20:53:04 +02:00
rst = { }
2020-07-18 08:14:23 +02:00
if self . _format == " rst " :
print ( " .. THIS DOCUMENT IS AUTO-GENERATED, DO NOT MODIFY " )
print ( " .. To change this document, please update the docstrings in the individual modules " )
2020-05-01 20:15:39 +02:00
for m in all_modules ( ) :
try :
2020-05-05 20:53:04 +02:00
module_type = " core "
2020-05-03 11:15:52 +02:00
filename = os . path . join ( basepath , " modules " , " core " , " {} .py " . format ( m ) )
2020-05-01 20:15:39 +02:00
if not os . path . exists ( filename ) :
2020-05-03 11:15:52 +02:00
filename = os . path . join (
basepath , " modules " , " contrib " , " {} .py " . format ( m )
)
2020-05-05 20:53:04 +02:00
module_type = " contrib "
2020-05-01 20:15:39 +02:00
if not os . path . exists ( filename ) :
2020-05-03 11:15:52 +02:00
log . warning ( " module {} not found " . format ( m ) )
2020-05-01 20:15:39 +02:00
continue
doc = None
with open ( filename ) as f :
tree = ast . parse ( f . read ( ) )
doc = ast . get_docstring ( tree )
if not doc :
2020-05-03 11:15:52 +02:00
log . warning ( " failed to find docstring for {} " . format ( m ) )
2020-05-01 20:15:39 +02:00
continue
2020-05-05 20:33:27 +02:00
if self . _format == " rst " :
2020-05-04 20:12:02 +02:00
if os . path . exists (
2020-05-23 16:55:24 +02:00
os . path . join ( basepath , " .. " , " screenshots " , " {} .png " . format ( m ) )
2020-05-04 20:12:02 +02:00
) :
2020-05-05 20:33:27 +02:00
doc = " {} \n \n .. image:: ../screenshots/ {} .png " . format ( doc , m )
2020-05-05 20:53:04 +02:00
rst [ module_type ] = rst . get ( module_type , [ ] )
2020-05-09 21:24:28 +02:00
rst [ module_type ] . append ( { " module " : m , " content " : doc } )
2020-05-01 20:15:39 +02:00
else :
2020-05-03 11:15:52 +02:00
print (
textwrap . fill (
" {} : " . format ( m ) ,
80 ,
initial_indent = self . _indent * 2 ,
subsequent_indent = self . _indent * 2 ,
)
)
for line in doc . split ( " \n " ) :
print (
textwrap . fill (
line ,
80 ,
initial_indent = self . _indent * 3 ,
subsequent_indent = self . _indent * 6 ,
)
)
2020-05-01 20:15:39 +02:00
except Exception as e :
log . warning ( e )
2020-05-05 20:53:04 +02:00
if self . _format == " rst " :
print ( " List of modules \n =============== " )
2020-05-09 21:24:28 +02:00
for k in [ " core " , " contrib " ] :
print ( " \n {} \n {} \n " . format ( k , " - " * len ( k ) ) )
2020-05-05 20:53:04 +02:00
for mod in rst [ k ] :
2020-05-09 21:24:28 +02:00
print ( " \n {} \n {} \n " . format ( mod [ " module " ] , " ~ " * len ( mod [ " module " ] ) ) )
2020-05-05 20:53:04 +02:00
print ( mod [ " content " ] )
2020-05-03 11:15:52 +02:00
2020-01-25 14:24:21 +01:00
class Config ( util . store . Store ) :
2020-05-10 13:25:13 +02:00
""" Represents the configuration of bumblebee-status (either via config file or via CLI)
: param args : The arguments passed via the commandline
"""
2020-01-19 15:36:52 +01:00
def __init__ ( self , args ) :
2020-01-25 14:24:21 +01:00
super ( Config , self ) . __init__ ( )
2020-05-03 11:15:52 +02:00
parser = argparse . ArgumentParser (
description = " bumblebee-status is a modular, theme-able status line generator for the i3 window manager. https://github.com/tobi-wan-kenobi/bumblebee-status/wiki "
)
2021-02-20 13:50:31 +01:00
parser . add_argument (
" -c " ,
" --config-file " ,
action = " store " ,
default = None ,
help = " Specify a configuration file to use "
)
2020-05-03 11:15:52 +02:00
parser . add_argument (
" -m " , " --modules " , nargs = " + " , action = " append " , default = [ ] , help = MODULE_HELP
)
parser . add_argument (
" -p " ,
" --parameters " ,
nargs = " + " ,
action = " append " ,
default = [ ] ,
help = PARAMETER_HELP ,
)
2020-07-09 06:56:43 +02:00
parser . add_argument ( " -t " , " --theme " , default = None , help = THEME_HELP )
2020-05-03 11:15:52 +02:00
parser . add_argument (
" -i " ,
" --iconset " ,
default = " auto " ,
help = " Specify the name of an iconset to use (overrides theme default) " ,
)
parser . add_argument (
" -a " ,
" --autohide " ,
nargs = " + " ,
default = [ ] ,
help = " Specify a list of modules to hide when not in warning/error state " ,
)
2021-01-17 15:21:40 +01:00
parser . add_argument (
" -e " ,
" --errorhide " ,
nargs = " + " ,
default = [ ] ,
help = " Specify a list of modules that are hidden when in state error "
)
2020-05-03 11:15:52 +02:00
parser . add_argument (
" -d " , " --debug " , action = " store_true " , help = " Add debug fields to i3 output "
)
parser . add_argument (
" -f " ,
" --logfile " ,
help = " destination for the debug log file, if -d|--debug is specified; defaults to stderr " ,
)
parser . add_argument (
" -r " ,
" --right-to-left " ,
action = " store_true " ,
help = " Draw widgets from right to left, rather than left to right (which is the default) " ,
)
parser . add_argument (
" -l " ,
" --list " ,
2020-05-05 20:33:27 +02:00
choices = [ " modules " , " themes " , " modules-rst " ] ,
2020-05-03 11:15:52 +02:00
help = " Display a list of available themes or available modules, along with their parameters " ,
action = print_usage ,
)
2020-05-01 15:17:55 +02:00
2020-04-04 13:54:08 +02:00
self . __args = parser . parse_args ( args )
2020-01-19 15:36:52 +01:00
2021-02-20 13:50:31 +01:00
if self . __args . config_file :
cfg = self . __args . config_file
2020-05-02 13:43:17 +02:00
cfg = os . path . expanduser ( cfg )
self . load_config ( cfg )
2021-02-20 13:50:31 +01:00
else :
for cfg in [
" ~/.bumblebee-status.conf " ,
" ~/.config/bumblebee-status.conf " ,
" ~/.config/bumblebee-status/config " ,
] :
cfg = os . path . expanduser ( cfg )
self . load_config ( cfg )
2020-05-02 13:43:17 +02:00
2020-05-03 11:15:52 +02:00
parameters = [ item for sub in self . __args . parameters for item in sub ]
2020-01-25 14:24:21 +01:00
for param in parameters :
2020-05-03 11:15:52 +02:00
if not " = " in param :
log . error (
' missing value for parameter " {} " - ignoring this parameter ' . format (
param
)
)
2020-04-08 11:50:00 +02:00
continue
2020-05-03 11:15:52 +02:00
key , value = param . split ( " = " , 1 )
2020-01-25 14:24:21 +01:00
self . set ( key , value )
2020-05-10 13:25:13 +02:00
""" Loads parameters from an init-style configuration file
: param filename : path to the file to load
"""
2020-05-02 13:43:17 +02:00
def load_config ( self , filename ) :
if os . path . exists ( filename ) :
2020-05-03 11:15:52 +02:00
log . info ( " loading {} " . format ( filename ) )
2020-05-02 13:43:17 +02:00
tmp = RawConfigParser ( )
2020-06-02 20:13:39 +02:00
tmp . read ( u " {} " . format ( filename ) )
2020-05-02 13:43:17 +02:00
2020-05-03 11:15:52 +02:00
if tmp . has_section ( " module-parameters " ) :
for key , value in tmp . items ( " module-parameters " ) :
2020-05-02 13:43:17 +02:00
self . set ( key , value )
2020-07-09 07:04:22 +02:00
if tmp . has_section ( " core " ) :
for key , value in tmp . items ( " core " ) :
self . set ( key , value )
2020-05-02 13:43:17 +02:00
2020-05-10 13:25:13 +02:00
""" Returns a list of configured modules
: return : list of configured ( active ) modules
: rtype : list of strings
"""
2020-01-19 15:36:52 +01:00
def modules ( self ) :
2020-07-09 07:04:45 +02:00
list_of_modules = [ item for sub in self . __args . modules for item in sub ]
if list_of_modules == [ ] :
list_of_modules = util . format . aslist ( self . get ( ' modules ' , [ ] ) )
2020-07-06 10:50:41 +02:00
return list_of_modules
2020-01-19 15:36:52 +01:00
2020-05-10 13:25:13 +02:00
""" Returns the global update interval
: return : update interval in seconds
: rtype : float
"""
2020-04-02 16:54:57 +02:00
def interval ( self , default = 1 ) :
2020-05-03 11:15:52 +02:00
return util . format . seconds ( self . get ( " interval " , default ) )
2020-02-09 13:46:56 +01:00
2020-05-10 13:25:13 +02:00
""" Returns whether debug mode is enabled
: return : True if debug is enabled , False otherwise
: rtype : boolean
"""
2020-03-29 14:13:21 +02:00
def debug ( self ) :
2020-04-04 13:54:08 +02:00
return self . __args . debug
2020-03-29 14:13:21 +02:00
2020-05-10 13:25:13 +02:00
""" Returns whether module order should be reversed/inverted
: return : True if modules should be reversed , False otherwise
: rtype : boolean
"""
2020-05-01 15:17:55 +02:00
def reverse ( self ) :
return self . __args . right_to_left
2020-05-10 13:25:13 +02:00
""" Returns the logfile location
: return : location where the logfile should be written
: rtype : string
"""
2020-05-01 09:41:06 +02:00
def logfile ( self ) :
return self . __args . logfile
2020-05-10 13:25:13 +02:00
""" Returns the configured theme name
: return : name of the configured theme
: rtype : string
"""
2020-02-09 13:46:56 +01:00
def theme ( self ) :
2020-07-09 06:56:43 +02:00
return self . __args . theme or self . get ( " theme " ) or " default "
2020-02-09 13:46:56 +01:00
2020-05-10 13:25:13 +02:00
""" Returns the configured iconset name
: return : name of the configured iconset
: rtype : string
"""
2020-02-09 13:46:56 +01:00
def iconset ( self ) :
2020-04-04 13:54:08 +02:00
return self . __args . iconset
2020-01-25 14:24:21 +01:00
2021-01-17 15:21:40 +01:00
""" Returns whether a module should be hidden if their state is not warning/critical
2020-05-10 13:25:13 +02:00
2021-01-17 15:21:40 +01:00
: return : True if module should be hidden automatically , False otherwise
: rtype : bool
2020-05-10 13:25:13 +02:00
"""
2020-03-15 14:01:09 +01:00
def autohide ( self , name ) :
2020-04-04 13:54:08 +02:00
return name in self . __args . autohide
2020-03-15 14:01:09 +01:00
2021-01-17 15:21:40 +01:00
""" Returns which modules should be hidden if they are in state error
: return : returns True if name should be hidden , False otherwise
: rtype : bool
"""
def errorhide ( self , name ) :
return name in self . __args . errorhide
2020-05-03 11:15:52 +02:00
2020-01-19 15:36:52 +01:00
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4