Compare commits

...

13 Commits
1.6.3 ... 2.0.3

Author SHA1 Message Date
66fddc07b9 v2.0.3 2014-05-26 15:03:24 -07:00
e56a07e909 update wakatime package to v2.0.1 2014-05-26 15:01:32 -07:00
64ea40b3f5 v2.0.2 2014-05-26 14:07:29 -07:00
17fd6ef8e1 disable queue until bug fixed 2014-05-26 14:06:36 -07:00
e5e399dfbe v2.0.1 2014-05-25 17:30:26 -07:00
bcf037e8a4 v2.0.0 2014-05-25 17:29:47 -07:00
7e678a38bd bump version of wakatime package to 2.0.0 2014-05-25 17:27:52 -07:00
533aaac313 change www.wakatime.com to wakatime.com 2014-03-14 13:36:20 -07:00
7f4f70cc85 add bsd license 2014-03-12 17:03:14 -07:00
4adb8a8796 v1.6.5 2014-03-05 13:55:08 -08:00
48e1993b24 upgrade external wakatime package to v1.0.1 2014-03-05 13:51:29 -08:00
8a3375bb23 v1.6.4 2014-02-05 01:03:05 -08:00
8bd54a7427 upgrade wakatime package to v1.0.0 for mercurial support 2014-02-05 01:01:47 -08:00
13 changed files with 311 additions and 38 deletions

View File

@ -3,6 +3,40 @@ History
-------
2.0.3 (2014-05-26)
++++++++++++++++++
- upgrade external wakatime package to v2.0.1
- fix bug in queue preventing completed tasks from being purged
2.0.2 (2014-05-26)
++++++++++++++++++
- disable syncing offline time until bug fixed
2.0.1 (2014-05-25)
++++++++++++++++++
- upgrade external wakatime package to v2.0.0
- offline time logging using sqlite3 to queue editor events
1.6.5 (2014-03-05)
++++++++++++++++++
- upgrade external wakatime package to v1.0.1
- use new domain wakatime.com
1.6.4 (2014-02-05)
++++++++++++++++++
- upgrade external wakatime package to v1.0.0
- support for mercurial revision control
1.6.3 (2014-01-15)
++++++++++++++++++

29
LICENSE Normal file
View File

@ -0,0 +1,29 @@
Copyright (c) 2014 Alan Hamlett https://wakatime.com
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided
with the distribution.
* Neither the names of Wakatime or WakaTime, nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -8,7 +8,7 @@ Installation
Heads Up! For Sublime Text 2 on Windows & Linux, WakaTime depends on [Python](http://www.python.org/getit/) being installed to work correctly.
1. Get an api key from: https://wakati.me
1. Get an api key from: https://wakatime.com/#apikey
2. Using [Sublime Package Control](http://wbond.net/sublime_packages/package_control):
@ -18,16 +18,16 @@ Heads Up! For Sublime Text 2 on Windows & Linux, WakaTime depends on [Python](ht
c) Type `wakatime`, then press `enter` with the `WakaTime` plugin selected.
3. You will see a prompt at the bottom asking for your [api key](https://www.wakati.me/#apikey). Enter your api key, then press `enter`.
3. You will see a prompt at the bottom asking for your [api key](https://wakatime.com/#apikey). Enter your api key, then press `enter`.
4. Use Sublime and your time will automatically be tracked for you.
5. Visit https://wakati.me to see your logged time.
5. Visit https://wakatime.com to see your logged time.
6. Consider installing [BIND9](https://help.ubuntu.com/community/BIND9ServerHowto#Caching_Server_configuration) to cache your repeated DNS requests: `sudo apt-get install bind9`
Screen Shots
------------
![Project Overview](https://www.wakati.me/static/img/ScreenShots/Screen Shot 2013-10-26 at 5.04.01 PM.png)
![Project Overview](https://wakatime.com/static/img/ScreenShots/Screen Shot 2013-10-26 at 5.04.01 PM.png)

View File

@ -1,11 +1,12 @@
""" ==========================================================
File: WakaTime.py
Description: Automatic time tracking for Sublime Text 2 and 3.
Maintainer: WakaTi.me <support@wakatime.com>
Website: https://www.wakati.me/
Maintainer: WakaTime <support@wakatime.com>
License: BSD, see LICENSE for more details.
Website: https://wakatime.com/
==========================================================="""
__version__ = '1.6.3'
__version__ = '2.0.3'
import sublime
import sublime_plugin

View File

@ -3,7 +3,7 @@
// This settings file will be overwritten when upgrading.
{
// Your api key from https://www.wakati.me/#apikey
// Your api key from https://wakatime.com/#apikey
// Set this in your User specific WakaTime.sublime-settings file.
"api_key": "",

View File

@ -3,6 +3,36 @@ History
-------
2.0.1 (2014-05-26)
++++++++++++++++++
- fix bug in queue preventing actions with NULL values from being purged
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)
++++++++++++++++++
- use new domain name wakatime.com
1.0.0 (2014-02-05)
++++++++++++++++++
- detect project name and branch name from mercurial revision control
0.5.3 (2014-01-15)
++++++++++++++++++

View File

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

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://www.wakati.me/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 Wakati.Me, 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__ = '0.5.3'
__version__ = '2.0.1'
__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 wakati.me api key; uses api_key from '+
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,9 +233,9 @@ 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):
url = 'https://www.wakati.me/api/v1/actions'
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 = {
'time': timestamp,
@ -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

@ -13,10 +13,6 @@ import logging
import os
from .base import BaseProject
try:
from collections import OrderedDict
except ImportError:
from ..packages.ordereddict import OrderedDict
log = logging.getLogger(__name__)

View File

@ -18,13 +18,41 @@ from .base import BaseProject
log = logging.getLogger(__name__)
# str is unicode in Python3
try:
unicode
except NameError:
unicode = str
class Mercurial(BaseProject):
def process(self):
return False
self.configDir = self._find_hg_config_dir(self.path)
return self.configDir is not None
def name(self):
if self.configDir:
return unicode(os.path.basename(os.path.dirname(self.configDir)))
return None
def branch(self):
return None
if self.configDir:
branch_file = os.path.join(self.configDir, 'branch')
try:
with open(branch_file) as fh:
return unicode(fh.readline().strip().rsplit('/', 1)[-1])
except IOError:
pass
return unicode('default')
def _find_hg_config_dir(self, path):
path = os.path.realpath(path)
if os.path.isfile(path):
path = os.path.split(path)[0]
if os.path.isdir(os.path.join(path, '.hg')):
return os.path.join(path, '.hg')
split_path = os.path.split(path)
if split_path[1] == '':
return None
return self._find_hg_config_dir(split_path[0])

View File

@ -0,0 +1,114 @@
# -*- 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
import traceback
from time import sleep
log = logging.getLogger(__name__)
class Queue(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 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):
try:
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()
except sqlite3.Error, e:
log.error(str(e))
def pop(self):
tries = 3
wait = 0.1
action = None
try:
conn, c = self.connect()
except sqlite3.Error, e:
log.debug(traceback.format_exc())
return None
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:
values = []
clauses = []
index = 0
for row_name in ['file', 'time', 'project', 'language', 'lines', 'branch', 'is_write']:
if row[index] is not None:
clauses.append('{0}=?'.format(row_name))
values.append(row[index])
else:
clauses.append('{0} IS NULL'.format(row_name))
index += 1
if len(values) > 0:
c.execute('DELETE FROM action WHERE {0}'.format(u' AND '.join(clauses)), values)
else:
c.execute('DELETE FROM action WHERE {0}'.format(u' AND '.join(clauses)))
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(traceback.format_exc())
sleep(wait)
tries -= 1
try:
conn.close()
except sqlite3.Error, e:
log.debug(traceback.format_exc())
return action