rana-cli/wakatime/__init__.py

201 lines
6.2 KiB
Python
Raw Normal View History

2013-07-06 07:51:09 +00:00
# -*- coding: utf-8 -*-
"""
wakatime
~~~~~~~~
Action event appender for Wakati.Me, auto time tracking for text editors.
2013-07-06 07:51:09 +00:00
:copyright: (c) 2013 Alan Hamlett.
:license: BSD, see LICENSE for more details.
"""
from __future__ import print_function
__title__ = 'wakatime'
2013-09-08 02:05:31 +00:00
__version__ = '0.4.5'
2013-07-06 07:51:09 +00:00
__author__ = 'Alan Hamlett'
__license__ = 'BSD'
__copyright__ = 'Copyright 2013 Alan Hamlett'
import base64
import logging
import os
import platform
import re
import sys
import time
import traceback
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'packages'))
2013-07-06 07:51:09 +00:00
from .log import setup_logging
from .project import find_project
2013-09-07 05:46:52 +00:00
from .packages import argparse
from .packages import simplejson as json
try:
from urllib2 import HTTPError, Request, urlopen
except ImportError:
from urllib.error import HTTPError
from urllib.request import Request, urlopen
2013-07-06 07:51:09 +00:00
log = logging.getLogger(__name__)
class FileAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
values = os.path.realpath(values)
setattr(namespace, self.dest, values)
def parseArguments(argv):
try:
sys.argv
except AttributeError:
sys.argv = argv
2013-07-06 07:51:09 +00:00
parser = argparse.ArgumentParser(
description='Wakati.Me event api appender')
parser.add_argument('--file', dest='targetFile', metavar='file',
action=FileAction, required=True,
help='absolute path to file for current action')
2013-07-06 07:51:09 +00:00
parser.add_argument('--time', dest='timestamp', metavar='time',
type=float,
help='optional floating-point unix epoch timestamp; '+
'uses current time by default')
parser.add_argument('--endtime', dest='endtime',
help='optional end timestamp turning this action into '+
'a duration; if a non-duration action occurs within a '+
2013-07-06 07:51:09 +00:00
'duration, the duration is ignored')
parser.add_argument('--write', dest='isWrite',
action='store_true',
help='note action was triggered from writing to a file')
2013-07-06 07:51:09 +00:00
parser.add_argument('--plugin', dest='plugin',
help='optional text editor plugin name and version '+
'for User-Agent header')
parser.add_argument('--key', dest='key',
help='your wakati.me api key; uses api_key from '+
'~/.wakatime.conf by default')
parser.add_argument('--logfile', dest='logfile',
help='defaults to ~/.wakatime.log')
parser.add_argument('--config', dest='config',
help='defaults to ~/.wakatime.conf')
parser.add_argument('--verbose', dest='verbose', action='store_true',
help='turns on debug messages in log file')
parser.add_argument('--version', action='version', version=__version__)
args = parser.parse_args(args=argv[1:])
2013-07-06 07:51:09 +00:00
if not args.timestamp:
args.timestamp = time.time()
if not args.key:
default_key = get_api_key(args.config)
if default_key:
args.key = default_key
else:
parser.error('Missing api key')
return args
def get_api_key(configFile):
if not configFile:
configFile = os.path.join(os.path.expanduser('~'), '.wakatime.conf')
2013-07-06 07:51:09 +00:00
api_key = None
try:
cf = open(configFile)
2013-07-06 07:51:09 +00:00
for line in cf:
line = line.split('=', 1)
if line[0] == 'api_key':
api_key = line[1].strip()
cf.close()
except IOError:
print('Error: Could not read from config file.')
2013-07-06 07:51:09 +00:00
return api_key
def get_user_agent(plugin):
2013-07-24 03:31:36 +00:00
ver = sys.version_info
python_version = '%d.%d.%d.%s.%d' % (ver[0], ver[1], ver[2], ver[3], ver[4])
user_agent = 'wakatime/%s (%s) Python%s' % (__version__,
platform.platform(), python_version)
2013-07-06 07:51:09 +00:00
if plugin:
user_agent = user_agent+' '+plugin
2013-07-06 07:51:09 +00:00
return user_agent
2013-08-15 07:09:27 +00:00
def send_action(project=None, branch=None, key=None, targetFile=None,
2013-07-06 07:51:09 +00:00
timestamp=None, endtime=None, isWrite=None, plugin=None, **kwargs):
2013-07-07 23:33:11 +00:00
url = 'https://www.wakati.me/api/v1/actions'
log.debug('Sending action to api at %s' % url)
2013-07-06 07:51:09 +00:00
data = {
'time': timestamp,
2013-07-06 07:51:09 +00:00
'file': targetFile,
}
if endtime:
data['endtime'] = endtime
if isWrite:
data['is_write'] = isWrite
if project:
data['project'] = project
2013-08-15 07:09:27 +00:00
if branch:
data['branch'] = branch
2013-07-06 07:51:09 +00:00
log.debug(data)
# setup api request
request = Request(url=url, data=str.encode(json.dumps(data)))
request.add_header('User-Agent', get_user_agent(plugin))
request.add_header('Content-Type', 'application/json')
2013-07-30 06:04:43 +00:00
auth = 'Basic %s' % bytes.decode(base64.b64encode(str.encode(key)))
request.add_header('Authorization', auth)
# log time to api
response = None
2013-07-06 07:51:09 +00:00
try:
response = urlopen(request)
except HTTPError as exc:
exception_data = {
'response_code': exc.getcode(),
sys.exc_info()[0].__name__: str(sys.exc_info()[1]),
}
if log.isEnabledFor(logging.DEBUG):
exception_data['traceback'] = traceback.format_exc()
log.error(exception_data)
except:
exception_data = {
2013-07-06 07:51:09 +00:00
sys.exc_info()[0].__name__: str(sys.exc_info()[1]),
}
if log.isEnabledFor(logging.DEBUG):
exception_data['traceback'] = traceback.format_exc()
log.error(exception_data)
2013-07-06 07:51:09 +00:00
else:
if response.getcode() == 201:
log.debug({
'response_code': response.getcode(),
})
return True
log.error({
'response_code': response.getcode(),
'response_content': response.read(),
2013-07-06 07:51:09 +00:00
})
return False
def main(argv=None):
if not argv:
argv = sys.argv
args = parseArguments(argv)
2013-07-06 07:51:09 +00:00
setup_logging(args, __version__)
if os.path.isfile(args.targetFile):
2013-08-15 07:09:27 +00:00
branch = None
name = None
2013-07-06 07:51:09 +00:00
project = find_project(args.targetFile)
if project:
2013-08-15 07:09:27 +00:00
branch = project.branch()
name = project.name()
2013-08-15 07:09:27 +00:00
if send_action(project=name, branch=branch, **vars(args)):
2013-07-07 23:33:11 +00:00
return 0
2013-07-06 07:51:09 +00:00
return 102
else:
log.debug('File does not exist; ignoring this action.')
2013-07-06 07:51:09 +00:00
return 101