upgrade wakatime-cli to v2.1.11 to fix offline logging

This commit is contained in:
Alan Hamlett 2014-12-22 00:55:59 -06:00
parent 62ea5345ba
commit 8b2357ec78
5 changed files with 54 additions and 41 deletions

View File

@ -3,6 +3,12 @@ History
------- -------
2.1.11 (2014-12-22)
+++++++++++++++++++
- fix offline logging when response from api is None
2.1.10 (2014-12-15) 2.1.10 (2014-12-15)
+++++++++++++++++++ +++++++++++++++++++

View File

@ -1,4 +1,6 @@
Copyright (c) 2013 Alan Hamlett https://wakatime.com BSD 3-Clause License
Copyright (c) 2014 by the respective authors (see AUTHORS file).
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -12,7 +14,7 @@ modification, are permitted provided that the following conditions are met:
in the documentation and/or other materials provided in the documentation and/or other materials provided
with the distribution. with the distribution.
* Neither the names of Wakatime or WakaTime, nor the names of its * Neither the names of WakaTime, nor the names of its
contributors may be used to endorse or promote products derived contributors may be used to endorse or promote products derived
from this software without specific prior written permission. from this software without specific prior written permission.

View File

@ -13,7 +13,7 @@
from __future__ import print_function from __future__ import print_function
__title__ = 'wakatime' __title__ = 'wakatime'
__version__ = '2.1.10' __version__ = '2.1.11'
__author__ = 'Alan Hamlett' __author__ = 'Alan Hamlett'
__license__ = 'BSD' __license__ = 'BSD'
__copyright__ = 'Copyright 2014 Alan Hamlett' __copyright__ = 'Copyright 2014 Alan Hamlett'
@ -142,14 +142,14 @@ def parseArguments(argv):
description='Common interface for the WakaTime api.') description='Common interface for the WakaTime api.')
parser.add_argument('--file', dest='targetFile', metavar='file', parser.add_argument('--file', dest='targetFile', metavar='file',
action=FileAction, required=True, action=FileAction, required=True,
help='absolute path to file for current action') help='absolute path to file for current heartbeat')
parser.add_argument('--time', dest='timestamp', metavar='time', parser.add_argument('--time', dest='timestamp', metavar='time',
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('--write', dest='isWrite', parser.add_argument('--write', dest='isWrite',
action='store_true', action='store_true',
help='note action was triggered from writing to a file') help='note heartbeat was triggered from writing to a file')
parser.add_argument('--plugin', dest='plugin', parser.add_argument('--plugin', dest='plugin',
help='optional text editor plugin name and version '+ help='optional text editor plugin name and version '+
'for User-Agent header') 'for User-Agent header')
@ -251,7 +251,7 @@ def get_user_agent(plugin):
return user_agent return user_agent
def send_action(project=None, branch=None, stats=None, key=None, targetFile=None, def send_action(project=None, branch=None, stats={}, key=None, targetFile=None,
timestamp=None, isWrite=None, plugin=None, offline=None, timestamp=None, isWrite=None, plugin=None, offline=None,
hidefilenames=None, **kwargs): hidefilenames=None, **kwargs):
url = 'https://wakatime.com/api/v1/actions' url = 'https://wakatime.com/api/v1/actions'
@ -270,6 +270,8 @@ def send_action(project=None, branch=None, stats=None, key=None, targetFile=None
data['lines'] = stats['lines'] data['lines'] = stats['lines']
if stats.get('language'): if stats.get('language'):
data['language'] = stats['language'] data['language'] = stats['language']
if stats.get('dependencies'):
data['dependencies'] = stats['dependencies']
if isWrite: if isWrite:
data['is_write'] = isWrite data['is_write'] = isWrite
if project: if project:
@ -310,9 +312,9 @@ def send_action(project=None, branch=None, stats=None, key=None, targetFile=None
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
exception_data['traceback'] = traceback.format_exc() exception_data['traceback'] = traceback.format_exc()
if offline: if offline:
if response is not None and response.getcode() != 400: if response is None or response.getcode() != 400:
queue = Queue() queue = Queue()
queue.push(data, plugin) queue.push(data, json.dumps(stats), plugin)
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.warn(exception_data) log.warn(exception_data)
if response is not None and response.getcode() in ALWAYS_LOG_CODES: if response is not None and response.getcode() in ALWAYS_LOG_CODES:
@ -328,9 +330,9 @@ def send_action(project=None, branch=None, stats=None, key=None, targetFile=None
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
exception_data['traceback'] = traceback.format_exc() exception_data['traceback'] = traceback.format_exc()
if offline: if offline:
if response is not None and response.getcode() != 400: if response is None or response.getcode() != 400:
queue = Queue() queue = Queue()
queue.push(data, plugin) queue.push(data, json.dumps(stats), plugin)
if 'unknown url type: https' in u(sys.exc_info()[1]): if 'unknown url type: https' in u(sys.exc_info()[1]):
log.error(exception_data) log.error(exception_data)
elif log.isEnabledFor(logging.DEBUG): elif log.isEnabledFor(logging.DEBUG):
@ -350,9 +352,9 @@ def send_action(project=None, branch=None, stats=None, key=None, targetFile=None
response_code = response.getcode() if response is not None else None response_code = response.getcode() if response is not None else None
response_content = response.read() if response is not None else None response_content = response.read() if response is not None else None
if offline: if offline:
if response is not None and response.getcode() != 400: if response is None or response.getcode() != 400:
queue = Queue() queue = Queue()
queue.push(data, plugin) queue.push(data, json.dumps(stats), plugin)
if log.isEnabledFor(logging.DEBUG): if log.isEnabledFor(logging.DEBUG):
log.warn({ log.warn({
'response_code': response_code, 'response_code': response_code,
@ -407,16 +409,17 @@ def main(argv=None):
): ):
queue = Queue() queue = Queue()
while True: while True:
action = queue.pop() heartbeat = queue.pop()
if action is None: if heartbeat is None:
break break
sent = send_action(project=action['project'], sent = send_action(project=heartbeat['project'],
targetFile=action['file'], targetFile=heartbeat['file'],
timestamp=action['time'], timestamp=heartbeat['time'],
branch=action['branch'], branch=heartbeat['branch'],
stats={'language': action['language'], 'lines': action['lines']}, stats=json.loads(heartbeat['stats']),
key=args.key, isWrite=action['is_write'], key=args.key,
plugin=action['plugin'], isWrite=heartbeat['is_write'],
plugin=heartbeat['plugin'],
offline=args.offline, offline=args.offline,
hidefilenames=args.hidefilenames) hidefilenames=args.hidefilenames)
if not sent: if not sent:
@ -426,5 +429,5 @@ def main(argv=None):
return 102 # api error return 102 # api error
else: else:
log.debug('File does not exist; ignoring this action.') log.debug('File does not exist; ignoring this heartbeat.')
return 0 return 0

View File

@ -32,35 +32,35 @@ class Queue(object):
def connect(self): def connect(self):
conn = sqlite3.connect(self.DB_FILE) conn = sqlite3.connect(self.DB_FILE)
c = conn.cursor() c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS action ( c.execute('''CREATE TABLE IF NOT EXISTS heartbeat (
file text, file text,
time real, time real,
project text, project text,
language text,
lines integer,
branch text, branch text,
is_write integer, is_write integer,
stats text,
misc text,
plugin text) plugin text)
''') ''')
return (conn, c) return (conn, c)
def push(self, data, plugin): def push(self, data, stats, plugin, misc=None):
if not HAS_SQL: if not HAS_SQL:
return return
try: try:
conn, c = self.connect() conn, c = self.connect()
action = { heartbeat = {
'file': data.get('file'), 'file': data.get('file'),
'time': data.get('time'), 'time': data.get('time'),
'project': data.get('project'), 'project': data.get('project'),
'language': data.get('language'),
'lines': data.get('lines'),
'branch': data.get('branch'), 'branch': data.get('branch'),
'is_write': 1 if data.get('is_write') else 0, 'is_write': 1 if data.get('is_write') else 0,
'stats': stats,
'misc': misc,
'plugin': plugin, 'plugin': plugin,
} }
c.execute('INSERT INTO action VALUES (:file,:time,:project,:language,:lines,:branch,:is_write,:plugin)', action) c.execute('INSERT INTO heartbeat VALUES (:file,:time,:project,:branch,:is_write,:stats,:misc,:plugin)', heartbeat)
conn.commit() conn.commit()
conn.close() conn.close()
except sqlite3.Error: except sqlite3.Error:
@ -72,7 +72,7 @@ class Queue(object):
return None return None
tries = 3 tries = 3
wait = 0.1 wait = 0.1
action = None heartbeat = None
try: try:
conn, c = self.connect() conn, c = self.connect()
except sqlite3.Error: except sqlite3.Error:
@ -82,13 +82,13 @@ class Queue(object):
while loop and tries > -1: while loop and tries > -1:
try: try:
c.execute('BEGIN IMMEDIATE') c.execute('BEGIN IMMEDIATE')
c.execute('SELECT * FROM action LIMIT 1') c.execute('SELECT * FROM heartbeat LIMIT 1')
row = c.fetchone() row = c.fetchone()
if row is not None: if row is not None:
values = [] values = []
clauses = [] clauses = []
index = 0 index = 0
for row_name in ['file', 'time', 'project', 'language', 'lines', 'branch', 'is_write']: for row_name in ['file', 'time', 'project', 'branch', 'is_write']:
if row[index] is not None: if row[index] is not None:
clauses.append('{0}=?'.format(row_name)) clauses.append('{0}=?'.format(row_name))
values.append(row[index]) values.append(row[index])
@ -96,19 +96,19 @@ class Queue(object):
clauses.append('{0} IS NULL'.format(row_name)) clauses.append('{0} IS NULL'.format(row_name))
index += 1 index += 1
if len(values) > 0: if len(values) > 0:
c.execute('DELETE FROM action WHERE {0}'.format(' AND '.join(clauses)), values) c.execute('DELETE FROM heartbeat WHERE {0}'.format(' AND '.join(clauses)), values)
else: else:
c.execute('DELETE FROM action WHERE {0}'.format(' AND '.join(clauses))) c.execute('DELETE FROM heartbeat WHERE {0}'.format(' AND '.join(clauses)))
conn.commit() conn.commit()
if row is not None: if row is not None:
action = { heartbeat = {
'file': row[0], 'file': row[0],
'time': row[1], 'time': row[1],
'project': row[2], 'project': row[2],
'language': row[3], 'branch': row[3],
'lines': row[4], 'is_write': True if row[4] is 1 else False,
'branch': row[5], 'stats': row[5],
'is_write': True if row[6] is 1 else False, 'misc': row[6],
'plugin': row[7], 'plugin': row[7],
} }
loop = False loop = False
@ -120,4 +120,4 @@ class Queue(object):
conn.close() conn.close()
except sqlite3.Error: except sqlite3.Error:
log.debug(traceback.format_exc()) log.debug(traceback.format_exc())
return action return heartbeat

View File

@ -89,8 +89,10 @@ def number_lines_in_file(file_name):
def get_file_stats(file_name): def get_file_stats(file_name):
dependencies = []
stats = { stats = {
'language': guess_language(file_name), 'language': guess_language(file_name),
'dependencies': dependencies,
'lines': number_lines_in_file(file_name), 'lines': number_lines_in_file(file_name),
} }
return stats return stats