Renamed and added default config file. default tip
authorEugen Sawin <sawine@me73.com>
Mon, 18 Jul 2011 01:03:37 +0200
changeset 141b45f8231179
parent 13 4ef9c2142059
Renamed and added default config file.
db.py
tim.py
     1.1 --- a/db.py	Wed Oct 06 16:07:36 2010 +0200
     1.2 +++ b/db.py	Mon Jul 18 01:03:37 2011 +0200
     1.3 @@ -1,5 +1,5 @@
     1.4  """
     1.5 -Database lib for cronrec.
     1.6 +Description: Database lib for cronrec.
     1.7  Author: Eugen Sawin (sawine@me73.com)
     1.8  Dependencies: libsqlite3-dev
     1.9  """
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/tim.py	Mon Jul 18 01:03:37 2011 +0200
     2.3 @@ -0,0 +1,226 @@
     2.4 +#!/usr/local/bin/python
     2.5 +# -*- coding: utf-8 -*-
     2.6 +
     2.7 +"""
     2.8 +Name: tim - A time recording tool, because time is money.
     2.9 +Author: Eugen Sawin <sawine@me73.com>
    2.10 +Dependencies: Python 2.7 and libsqlite3-dev
    2.11 +"""
    2.12 +
    2.13 +import os
    2.14 +import sys
    2.15 +import argparse
    2.16 +from datetime import datetime
    2.17 +
    2.18 +import db
    2.19 +
    2.20 +def main():
    2.21 +	global config
    2.22 +	config = read_config()
    2.23 +	parser = argparse.ArgumentParser(description="Records time.")
    2.24 +	subs = parser.add_subparsers()
    2.25 +
    2.26 +	sub_init = subs.add_parser("init")
    2.27 +	sub_init.add_argument("working_path")
    2.28 +	sub_init.set_defaults(func=init)
    2.29 +
    2.30 +	sub_begin = subs.add_parser("begin")
    2.31 +	sub_begin.add_argument("label")
    2.32 +	sub_begin.set_defaults(func=begin)
    2.33 +
    2.34 +	sub_end = subs.add_parser("end")
    2.35 +	sub_end.add_argument("label", nargs="?", default="all:all")
    2.36 +	sub_end.add_argument("-m")
    2.37 +	sub_end.set_defaults(func=end)
    2.38 +
    2.39 +	sub_pause = subs.add_parser("pause")
    2.40 +	sub_pause.set_defaults(func=pause)
    2.41 +
    2.42 +	sub_resume = subs.add_parser("resume")
    2.43 +	sub_resume.add_argument("-m")
    2.44 +	sub_resume.set_defaults(func=resume)
    2.45 +
    2.46 +	sub_add = subs.add_parser("add")
    2.47 +	sub_add_subs = sub_add.add_subparsers()
    2.48 +
    2.49 +	sub_add_task = sub_add_subs.add_parser("task")
    2.50 +	sub_add_task.add_argument("label")
    2.51 +	sub_add_task.add_argument("begin")
    2.52 +	sub_add_task.add_argument("end")
    2.53 +	sub_add_task.add_argument("-m")
    2.54 +	sub_add_task.set_defaults(func=add_task)
    2.55 +	
    2.56 +	sub_add_break = sub_add_subs.add_parser("break")
    2.57 +	sub_add_break.add_argument("begin")
    2.58 +	sub_add_break.add_argument("end")
    2.59 +	sub_add_break.add_argument("-m")
    2.60 +	sub_add_break.set_defaults(func=add_break)
    2.61 +
    2.62 +	sub_set = subs.add_parser("set")
    2.63 +	sub_set_subs = sub_set.add_subparsers()
    2.64 +
    2.65 +	sub_set_customer = sub_set_subs.add_parser("customer")
    2.66 +	sub_set_customer.add_argument("project")
    2.67 +	sub_set_customer.add_argument("customer")
    2.68 +	sub_set_customer.set_defaults(func=set_customer)
    2.69 +
    2.70 +	sub_set_rate = sub_set_subs.add_parser("rate")
    2.71 +	sub_set_rate.add_argument("label")
    2.72 +	sub_set_rate.add_argument("rate", type=float)
    2.73 +	sub_set_rate.add_argument("currency")
    2.74 +	sub_set_rate.add_argument("type")
    2.75 +	sub_set_rate.set_defaults(func=set_rate)
    2.76 +
    2.77 +	sub_status = subs.add_parser("status")
    2.78 +	sub_status.set_defaults(func=status)
    2.79 +
    2.80 +	args = parser.parse_args()
    2.81 +	args.func(args)
    2.82 +
    2.83 +WD = "working_path"
    2.84 +CONFIG = {WD: str}
    2.85 +CONFIG_SEP = "="
    2.86 +DB_FILE = "tim.db"
    2.87 +
    2.88 +CURRENCIES = {("EUR", "EURO", "€"): "EUR",
    2.89 +("US DOLLAR", "USD", "$"): "USD"}
    2.90 +
    2.91 +RATE_TYPES = {("h", "hourly"): "hourly"}
    2.92 +
    2.93 +config = {}
    2.94 +
    2.95 +# Try to get the user's home directory path
    2.96 +try: # Windows
    2.97 +	from win32com.shell import shellcon, shell
    2.98 +	HOMEDIR	= shell.SHGetFolderPath(0, shellcon.CSIDL_LOCAL_APPDATA, 0, 0)
    2.99 +except ImportError: # Linux (hopefully)
   2.100 +	HOMEDIR = os.path.expanduser("~")
   2.101 +
   2.102 +CONFIG_FILE = "%s/.timrc" % HOMEDIR
   2.103 +
   2.104 +DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
   2.105 +
   2.106 +def read_config():
   2.107 +	config = {}
   2.108 +	if not os.path.isfile(CONFIG_FILE):
   2.109 +		write_config(config)
   2.110 +	with open(CONFIG_FILE, "r") as config_stream:
   2.111 +		config_lines = [l.split(CONFIG_SEP) for l in config_stream.readlines() 
   2.112 +						if CONFIG_SEP in l]
   2.113 +		for key, value in config_lines:
   2.114 +			key = key.strip().lower()
   2.115 +			value = value.strip()
   2.116 +			if key in CONFIG:
   2.117 +				config[key] = CONFIG[key](value)
   2.118 +	return config
   2.119 +
   2.120 +def write_config(config):
   2.121 +	with open(CONFIG_FILE, "w") as config_input:
   2.122 +		config_input.write("\n".join([CONFIG_SEP.join((k, v)) 
   2.123 +							for k, v in config.iteritems() if k in CONFIG]))
   2.124 +
   2.125 +def db_file():
   2.126 +	global config
   2.127 +	if WD not in config:
   2.128 +		print "Working directory path is not configured. \
   2.129 +Please use the init command."
   2.130 +		return None
   2.131 +	return config[WD] + "/" + DB_FILE
   2.132 +	
   2.133 +def init(args):
   2.134 +	global config
   2.135 +	last_wd = None
   2.136 +	if WD in config:
   2.137 +		last_wd = config[WD]
   2.138 +	config[WD] = args.working_path
   2.139 +	write_config(config)
   2.140 +	path_exists = os.path.exists(config[WD]) and os.path.isdir(config[WD])
   2.141 +	db_exists = path_exists and os.path.exists(db_file())\
   2.142 +				and os.path.isfile(db_file())
   2.143 +	if last_wd != config[WD]:		
   2.144 +		print "Changed working directory from %s to %s." % (last_wd, config[WD])
   2.145 +	else:
   2.146 +		print "Working directory remains at %s." % config[WD]
   2.147 +	if not path_exists:
   2.148 +		print "Warning: working directory %s does not exist." % config[WD]
   2.149 +		os.makedirs(config[WD])
   2.150 +		print "Working directory %s created." % config[WD]
   2.151 +	elif db_exists:
   2.152 +		print "Database file %s already exists, please delete it before \
   2.153 +initiating a new database at this location." % db_file()
   2.154 +	if not db_exists:
   2.155 +		db.init(db_file())	
   2.156 +
   2.157 +def parse_label(label):
   2.158 +	label = label.strip()
   2.159 +	if ":" in label:
   2.160 +		project, activity = label.split(":")
   2.161 +	else:
   2.162 +		project, activity = (label, None)
   2.163 +	return project, activity
   2.164 +
   2.165 +def begin(args):
   2.166 +	project, activity = parse_label(args.label)
   2.167 +	time = datetime.now()
   2.168 +	db.resume(db_file(), None, None, time)
   2.169 +	db.begin(db_file(), project, activity, time)	
   2.170 +    
   2.171 +def end(args):
   2.172 +	project, activity = parse_label(args.label)
   2.173 +	log = args.m	
   2.174 +	time = datetime.now()
   2.175 +	db.resume(db_file(), db.find_active_task(db_file()), time, log)
   2.176 +	db.end(db_file(), project, activity, time, log)	
   2.177 +
   2.178 +def pause(args):
   2.179 +	db.pause(db_file(), datetime.now())	 
   2.180 +
   2.181 +def resume(args):
   2.182 +	db.resume(db_file(), None, datetime.now(), args.m)	
   2.183 +
   2.184 +def add_task(args):
   2.185 +	project, activity = parse_label(args.label)
   2.186 +	log = args.m
   2.187 +	begin = datetime.strptime(args.begin, DATETIME_FORMAT)
   2.188 +	end = datetime.strptime(args.end, DATETIME_FORMAT)
   2.189 +	db.begin(db_file(), project, activity, begin)
   2.190 +	db.end(db_file(), project, activity, end, log)
   2.191 +
   2.192 +def add_break(args):
   2.193 +	log = args.m
   2.194 +	begin = datetime.strptime(args.begin, DATETIME_FORMAT)
   2.195 +	end = datetime.strptime(args.end, DATETIME_FORMAT)
   2.196 +	db.pause(db_file(), begin)
   2.197 +	db.resume(db_file(), db.find_active_task(db_file(), begin), end, log)
   2.198 +
   2.199 +def set_customer(args):
   2.200 +	db.update_where(db_file(), "projects", "name", args.project, "customer", 
   2.201 +				args.customer)
   2.202 +
   2.203 +def map_name(map_base, name):
   2.204 +	mapped = None
   2.205 +	if name not in map_base.itervalues():
   2.206 +		for v in map_base.iterkeys():
   2.207 +			if name in v:
   2.208 +				mapped = map_base[v]
   2.209 +	else:
   2.210 +		mapped = name
   2.211 +	return mapped
   2.212 +
   2.213 +def set_rate(args):
   2.214 +	project, activity = parse_label(args.label)
   2.215 +	currency = map_name(CURRENCIES, args.currency)
   2.216 +	type = map_name(RATE_TYPES, args.type)
   2.217 +	print "setting rate for %s at %f %s %s" % (project, args.rate, currency, type)
   2.218 +	db.set_rate(db_file(), project, activity, args.rate, currency, type)
   2.219 +
   2.220 +def status(args):
   2.221 +	task = db.status(db_file())
   2.222 +	if task:
   2.223 +		print "Currently active task"
   2.224 +		print "Project: %s Activity: %s" % task
   2.225 +	else:
   2.226 +		print "There is no active task."
   2.227 +
   2.228 +if __name__ == "__main__":
   2.229 +	main()