bump version of wakatime package to 2.0.0

This commit is contained in:
Alan Hamlett 2014-05-25 17:27:52 -07:00
parent 533aaac313
commit 7e678a38bd
5 changed files with 166 additions and 20 deletions

View File

@ -3,6 +3,18 @@ History
-------
2.0.0 (2014-05-25)
++++++++++++++++++
- offline time logging using sqlite3 to queue editor events
1.0.2 (2014-05-06)
++++++++++++++++++
- ability to set project from command line argument
1.0.1 (2014-03-05)
++++++++++++++++++

View File

@ -1,9 +1,9 @@
WakaTime
========
Fully automatic time tracking for your text editor.
Fully automatic time tracking for programmers.
This is the common interface for the WakaTime api. You shouldn't need to directly use this package unless you are creating a new plugin.
This is the common interface for the WakaTime api. You shouldn't need to directly use this package unless you are creating a new plugin or your text editor's plugin asks you to install the wakatime-cli interface.
Go to http://wakatime.com to install the plugin for your text editor.
@ -11,4 +11,10 @@ Go to http://wakatime.com to install the plugin for your text editor.
Installation
------------
https://wakatime.com/help/plugins/installing-plugins
pip install wakatime
Usage
-----
https://wakatime.com/

View File

@ -11,13 +11,10 @@ setup(
name='wakatime',
version=VERSION,
license='BSD 3 Clause',
description=' '.join([
'Action event appender for WakaTime, a time',
'tracking api for text editors.',
]),
description='Interface to the WakaTime api.',
long_description=open('README.rst').read(),
author='Alan Hamlett',
author_email='alan.hamlett@gmail.com',
author_email='alan@wakatime.com',
url='https://github.com/wakatime/wakatime',
packages=packages,
package_dir={'wakatime': 'wakatime'},
@ -28,7 +25,7 @@ setup(
'console_scripts': ['wakatime = wakatime.__init__:main'],
},
classifiers=(
'Development Status :: 3 - Alpha',
'Development Status :: 5 - Production/Stable',
'Environment :: Console',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',

View File

@ -13,10 +13,10 @@
from __future__ import print_function
__title__ = 'wakatime'
__version__ = '1.0.1'
__version__ = '2.0.0'
__author__ = 'Alan Hamlett'
__license__ = 'BSD'
__copyright__ = 'Copyright 2013 Alan Hamlett'
__copyright__ = 'Copyright 2014 Alan Hamlett'
import base64
@ -39,6 +39,7 @@ except ImportError:
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'))
from .queue import Queue
from .log import setup_logging
from .project import find_project
from .stats import get_file_stats
@ -148,9 +149,14 @@ def parseArguments(argv):
parser.add_argument('--plugin', dest='plugin',
help='optional text editor plugin name and version '+
'for User-Agent header')
parser.add_argument('--project', dest='project_name',
help='optional project name; will auto-discover by default')
parser.add_argument('--key', dest='key',
help='your wakatime api key; uses api_key from '+
'~/.wakatime.conf by default')
parser.add_argument('--disableoffline', dest='offline',
action='store_false',
help='disables offline time logging instead of queuing logged time')
parser.add_argument('--ignore', dest='ignore', action='append',
help='filename patterns to ignore; POSIX regex syntax; can be used more than once')
parser.add_argument('--logfile', dest='logfile',
@ -191,6 +197,8 @@ def parseArguments(argv):
args.ignore.append(pattern)
except TypeError:
pass
if args.offline and configs.has_option('settings', 'offline'):
args.offline = configs.getboolean('settings', 'offline')
if not args.verbose and configs.has_option('settings', 'verbose'):
args.verbose = configs.getboolean('settings', 'verbose')
if not args.verbose and configs.has_option('settings', 'debug'):
@ -225,8 +233,8 @@ def get_user_agent(plugin):
return user_agent
def send_action(project=None, branch=None, stats={}, key=None, targetFile=None,
timestamp=None, isWrite=None, plugin=None, **kwargs):
def send_action(project=None, branch=None, stats=None, key=None, targetFile=None,
timestamp=None, isWrite=None, plugin=None, offline=None, **kwargs):
url = 'https://wakatime.com/api/v1/actions'
log.debug('Sending action to api at %s' % url)
data = {
@ -268,24 +276,45 @@ def send_action(project=None, branch=None, stats={}, key=None, targetFile=None,
}
if log.isEnabledFor(logging.DEBUG):
exception_data['traceback'] = traceback.format_exc()
log.error(exception_data)
if offline:
queue = Queue()
queue.push(data, plugin)
if log.isEnabledFor(logging.DEBUG):
log.warn(exception_data)
else:
log.error(exception_data)
except:
exception_data = {
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)
if offline:
queue = Queue()
queue.push(data, plugin)
if log.isEnabledFor(logging.DEBUG):
log.warn(exception_data)
else:
log.error(exception_data)
else:
if response.getcode() == 201:
log.debug({
'response_code': response.getcode(),
})
return True
log.error({
'response_code': response.getcode(),
'response_content': response.read(),
})
if offline:
queue = Queue()
queue.push(data, plugin)
if log.isEnabledFor(logging.DEBUG):
log.warn({
'response_code': response.getcode(),
'response_content': response.read(),
})
else:
log.error({
'response_code': response.getcode(),
'response_content': response.read(),
})
return False
@ -313,7 +342,7 @@ def main(argv=None):
project_name = None
if project:
branch = project.branch()
project_name = project.name()
project_name = args.project_name or project.name()
if send_action(
project=project_name,
@ -321,6 +350,15 @@ def main(argv=None):
stats=stats,
**vars(args)
):
queue = Queue()
while True:
action = queue.pop()
if action is None:
break
if not send_action(project=action['project'], targetFile=action['file'], timestamp=action['time'],
branch=action['branch'], stats={'language': action['language'], 'lines': action['lines']},
key=args.key, isWrite=action['is_write'], plugin=action['plugin'], offline=args.offline):
break
return 0 # success
return 102 # api error

View File

@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-
"""
wakatime.queue
~~~~~~~~~~~~~~
Queue for offline time logging.
http://wakatime.com
:copyright: (c) 2014 Alan Hamlett.
:license: BSD, see LICENSE for more details.
"""
import logging
import os
import sqlite3
from time import sleep
log = logging.getLogger(__name__)
class Queue(object):
DB_FILE = os.path.join(os.path.expanduser('~'), '.wakatime.db')
def connect(self):
exists = os.path.exists(self.DB_FILE)
conn = sqlite3.connect(self.DB_FILE)
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS action (
file text,
time real,
project text,
language text,
lines integer,
branch text,
is_write integer,
plugin text)
''')
return (conn, c)
def push(self, data, plugin):
conn, c = self.connect()
action = {
'file': data.get('file'),
'time': data.get('time'),
'project': data.get('project'),
'language': data.get('language'),
'lines': data.get('lines'),
'branch': data.get('branch'),
'is_write': 1 if data.get('is_write') else 0,
'plugin': plugin,
}
c.execute('INSERT INTO action VALUES (:file,:time,:project,:language,:lines,:branch,:is_write,:plugin)', action)
conn.commit()
conn.close()
def pop(self):
tries = 3
wait = 0.1
action = None
conn, c = self.connect()
loop = True
while loop and tries > -1:
try:
c.execute('BEGIN IMMEDIATE')
c.execute('SELECT * FROM action LIMIT 1')
row = c.fetchone()
if row is not None:
c.execute('''DELETE FROM action WHERE
file=? AND time=? AND project=? AND language=? AND
lines=? AND branch=? AND is_write=?''', row[0:7])
conn.commit()
if row is not None:
action = {
'file': row[0],
'time': row[1],
'project': row[2],
'language': row[3],
'lines': row[4],
'branch': row[5],
'is_write': True if row[6] is 1 else False,
'plugin': row[7],
}
loop = False
except sqlite3.Error, e:
log.debug(str(e))
sleep(wait)
tries -= 1
conn.close()
return action