upgrade wakatime cli to v4.0.11

This commit is contained in:
Alan Hamlett 2015-05-12 15:02:09 -07:00
parent 12cbeb1ce3
commit 81f2c1fbeb
6 changed files with 151 additions and 19 deletions

View File

@ -1,7 +1,7 @@
__title__ = 'wakatime' __title__ = 'wakatime'
__description__ = 'Common interface to the WakaTime api.' __description__ = 'Common interface to the WakaTime api.'
__url__ = 'https://github.com/wakatime/wakatime' __url__ = 'https://github.com/wakatime/wakatime'
__version_info__ = ('4', '0', '8') __version_info__ = ('4', '0', '11')
__version__ = '.'.join(__version_info__) __version__ = '.'.join(__version_info__)
__author__ = 'Alan Hamlett' __author__ = 'Alan Hamlett'
__author_email__ = 'alan@wakatime.com' __author_email__ = 'alan@wakatime.com'

View File

@ -29,14 +29,14 @@ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'pac
from .__about__ import __version__ from .__about__ import __version__
from .compat import u, open, is_py3 from .compat import u, open, is_py3
from .offlinequeue import Queue
from .logger import setup_logging from .logger import setup_logging
from .project import find_project from .offlinequeue import Queue
from .stats import get_file_stats
from .packages import argparse from .packages import argparse
from .packages import simplejson as json from .packages import simplejson as json
from .packages import requests
from .packages.requests.exceptions import RequestException from .packages.requests.exceptions import RequestException
from .project import find_project
from .session_cache import SessionCache
from .stats import get_file_stats
try: try:
from .packages import tzlocal from .packages import tzlocal
except: except:
@ -147,6 +147,10 @@ def parseArguments(argv):
type=float, type=float,
help='optional floating-point unix epoch timestamp; '+ help='optional floating-point unix epoch timestamp; '+
'uses current time by default') 'uses current time by default')
parser.add_argument('--lineno', dest='lineno',
help='optional line number; current line being edited')
parser.add_argument('--cursorpos', dest='cursorpos',
help='optional cursor position in the current file')
parser.add_argument('--notfile', dest='notfile', action='store_true', parser.add_argument('--notfile', dest='notfile', action='store_true',
help='when set, will accept any value for the file. for example, '+ help='when set, will accept any value for the file. for example, '+
'a domain name or other item you want to log time towards.') 'a domain name or other item you want to log time towards.')
@ -322,6 +326,10 @@ def send_heartbeat(project=None, branch=None, stats={}, key=None, targetFile=Non
data['language'] = stats['language'] data['language'] = stats['language']
if stats.get('dependencies'): if stats.get('dependencies'):
data['dependencies'] = stats['dependencies'] data['dependencies'] = stats['dependencies']
if stats.get('lineno'):
data['lineno'] = stats['lineno']
if stats.get('cursorpos'):
data['cursorpos'] = stats['cursorpos']
if isWrite: if isWrite:
data['is_write'] = isWrite data['is_write'] = isWrite
if project: if project:
@ -352,10 +360,13 @@ def send_heartbeat(project=None, branch=None, stats={}, key=None, targetFile=Non
if tz: if tz:
headers['TimeZone'] = u(tz.zone) headers['TimeZone'] = u(tz.zone)
session_cache = SessionCache()
session = session_cache.get()
# log time to api # log time to api
response = None response = None
try: try:
response = requests.post(api_url, data=request_body, headers=headers, response = session.post(api_url, data=request_body, headers=headers,
proxies=proxies) proxies=proxies)
except RequestException: except RequestException:
exception_data = { exception_data = {
@ -377,6 +388,7 @@ def send_heartbeat(project=None, branch=None, stats={}, key=None, targetFile=Non
log.debug({ log.debug({
'response_code': response_code, 'response_code': response_code,
}) })
session_cache.save(session)
return True return True
if offline: if offline:
if response_code != 400: if response_code != 400:
@ -402,6 +414,7 @@ def send_heartbeat(project=None, branch=None, stats={}, key=None, targetFile=Non
'response_code': response_code, 'response_code': response_code,
'response_content': response_content, 'response_content': response_content,
}) })
session_cache.delete()
return False return False
@ -424,7 +437,8 @@ def main(argv=None):
if os.path.isfile(args.targetFile) or args.notfile: if os.path.isfile(args.targetFile) or args.notfile:
stats = get_file_stats(args.targetFile, notfile=args.notfile) stats = get_file_stats(args.targetFile, notfile=args.notfile,
lineno=args.lineno, cursorpos=args.cursorpos)
project = None project = None
if not args.notfile: if not args.notfile:

View File

@ -9,6 +9,7 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
import inspect
import logging import logging
import os import os
import sys import sys
@ -47,14 +48,19 @@ class JsonFormatter(logging.Formatter):
def format(self, record): def format(self, record):
data = OrderedDict([ data = OrderedDict([
('now', self.formatTime(record, self.datefmt)), ('now', self.formatTime(record, self.datefmt)),
('version', self.version),
('plugin', self.plugin),
('time', self.timestamp),
('isWrite', self.isWrite),
('file', self.targetFile),
('level', record.levelname),
('message', record.msg),
]) ])
try:
data['package'] = inspect.stack()[9][0].f_globals.get('__package__')
data['lineno'] = inspect.stack()[9][2]
except:
pass
data['version'] = self.version
data['plugin'] = self.plugin
data['time'] = self.timestamp
data['isWrite'] = self.isWrite
data['file'] = self.targetFile
data['level'] = record.levelname
data['message'] = record.msg
if not self.plugin: if not self.plugin:
del data['plugin'] del data['plugin']
if not self.isWrite: if not self.isWrite:

View File

@ -1,10 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
wakatime.queue wakatime.offlinequeue
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
Queue for offline time logging. Queue for saving heartbeats while offline.
http://wakatime.com
:copyright: (c) 2014 Alan Hamlett. :copyright: (c) 2014 Alan Hamlett.
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.

View File

@ -0,0 +1,109 @@
# -*- coding: utf-8 -*-
"""
wakatime.session_cache
~~~~~~~~~~~~~~~~~~~~~~
Persist requests.Session for multiprocess SSL handshake pooling.
:copyright: (c) 2015 Alan Hamlett.
:license: BSD, see LICENSE for more details.
"""
import logging
import os
import pickle
import sys
import traceback
try:
import sqlite3
HAS_SQL = True
except ImportError:
HAS_SQL = False
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'packages'))
from .packages import requests
log = logging.getLogger('WakaTime')
class SessionCache(object):
DB_FILE = os.path.join(os.path.expanduser('~'), '.wakatime.db')
def connect(self):
conn = sqlite3.connect(self.DB_FILE)
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS session (
value BLOB)
''')
return (conn, c)
def save(self, session):
"""Saves a requests.Session object for the next heartbeat process.
"""
if not HAS_SQL:
return
try:
conn, c = self.connect()
c.execute('DELETE FROM session')
values = {
'value': pickle.dumps(session),
}
c.execute('INSERT INTO session VALUES (:value)', values)
conn.commit()
conn.close()
except:
log.error(traceback.format_exc())
def get(self):
"""Returns a requests.Session object.
Gets Session from sqlite3 cache or creates a new Session.
"""
if not HAS_SQL:
return requests.session()
try:
conn, c = self.connect()
except:
log.error(traceback.format_exc())
return requests.session()
session = None
try:
c.execute('BEGIN IMMEDIATE')
c.execute('SELECT value FROM session LIMIT 1')
row = c.fetchone()
if row is not None:
session = pickle.loads(row[0])
except:
log.error(traceback.format_exc())
try:
conn.close()
except:
log.error(traceback.format_exc())
return session if session is not None else requests.session()
def delete(self):
"""Clears all cached Session objects.
"""
if not HAS_SQL:
return
try:
conn, c = self.connect()
c.execute('DELETE FROM session')
conn.commit()
conn.close()
except:
log.error(traceback.format_exc())

View File

@ -86,12 +86,14 @@ def number_lines_in_file(file_name):
return lines return lines
def get_file_stats(file_name, notfile=False): def get_file_stats(file_name, notfile=False, lineno=None, cursorpos=None):
if notfile: if notfile:
stats = { stats = {
'language': None, 'language': None,
'dependencies': [], 'dependencies': [],
'lines': None, 'lines': None,
'lineno': lineno,
'cursorpos': cursorpos,
} }
else: else:
language, lexer = guess_language(file_name) language, lexer = guess_language(file_name)
@ -101,5 +103,7 @@ def get_file_stats(file_name, notfile=False):
'language': language, 'language': language,
'dependencies': dependencies, 'dependencies': dependencies,
'lines': number_lines_in_file(file_name), 'lines': number_lines_in_file(file_name),
'lineno': lineno,
'cursorpos': cursorpos,
} }
return stats return stats