Merge pull request #4 from 3onyc/feature/projectmap

Add a ProjectMap plugin
This commit is contained in:
Alan Hamlett 2013-12-13 03:14:02 -08:00
commit ce4d6ce3b7
4 changed files with 105 additions and 30 deletions

View file

@ -27,6 +27,8 @@ import sys
import time import time
import traceback import traceback
from ConfigParser import RawConfigParser
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) 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')) sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'packages'))
from .log import setup_logging from .log import setup_logging
@ -51,16 +53,29 @@ class FileAction(argparse.Action):
values = os.path.realpath(values) values = os.path.realpath(values)
setattr(namespace, self.dest, values) setattr(namespace, self.dest, values)
def checkUpdateConfigFile(configFile):
"""Checks if the config has a header section, if not add it for ConfigParser"""
with open(configFile) as fh:
configData = fh.read()
if not configData.strip().startswith('[settings]'):
configData = "[settings]\n" + configData.strip()
with open(configFile, 'w') as fh:
fh.write(configData)
def parseConfigFile(configFile): def parseConfigFile(configFile):
if not configFile: if not configFile:
configFile = os.path.join(os.path.expanduser('~'), '.wakatime.conf') configFile = os.path.join(os.path.expanduser('~'), '.wakatime.conf')
checkUpdateConfigFile(configFile)
# define default config values # define default config values
configs = { defaults = {
'api_key': None, 'settings' : {
'ignore': [], 'api_key': None,
'verbose': False, 'ignore': [],
'verbose': False
},
} }
if not os.path.isfile(configFile): if not os.path.isfile(configFile):
@ -68,24 +83,19 @@ def parseConfigFile(configFile):
try: try:
with open(configFile) as fh: with open(configFile) as fh:
for line in fh: configs = RawConfigParser()
line = line.split('=', 1) setConfigDefaults(configs, defaults)
if len(line) == 2 and line[0].strip() and line[1].strip(): configs.readfp(fh)
line[0] = line[0].strip()
line[1] = line[1].strip()
if line[0] in configs:
if isinstance(configs[line[0]], list):
configs[line[0]].append(line[1])
elif isinstance(configs[line[0]], bool):
configs[line[0]] = True if line[1].lower() == 'true' else False
else:
configs[line[0]] = line[1]
else:
configs[line[0]] = line[1]
except IOError: except IOError:
print('Error: Could not read from config file ~/.wakatime.conf') print('Error: Could not read from config file ~/.wakatime.conf')
return configs return configs
def setConfigDefaults(config, defaults):
for section, values in defaults.iteritems():
if not config.has_section(section):
config.add_section(section)
for key, value in values.iteritems():
config.set(section, key, value)
def parseArguments(argv): def parseArguments(argv):
try: try:
@ -126,20 +136,21 @@ def parseArguments(argv):
# set arguments from config file # set arguments from config file
configs = parseConfigFile(args.config) configs = parseConfigFile(args.config)
if not args.key: if not args.key:
default_key = configs.get('api_key') default_key = configs.get('settings', 'api_key')
if default_key: if default_key:
args.key = default_key args.key = default_key
else: else:
parser.error('Missing api key') parser.error('Missing api key')
for pattern in configs.get('ignore', []): for pattern in configs.get('settings', 'ignore'):
if not args.ignore: if not args.ignore:
args.ignore = [] args.ignore = []
args.ignore.append(pattern) args.ignore.append(pattern)
if not args.verbose and 'verbose' in configs: if not args.verbose and configs.has_option('settings', 'verbose'):
args.verbose = configs['verbose'] args.verbose = configs.getboolean('settings', 'verbose')
if not args.logfile and 'logfile' in configs: if not args.logfile and configs.has_option('settings', 'logfile'):
args.logfile = configs['logfile'] args.logfile = configs.get('settings', 'logfile')
return args
return args, configs
def should_ignore(fileName, patterns): def should_ignore(fileName, patterns):
@ -233,7 +244,7 @@ def send_action(project=None, branch=None, stats={}, key=None, targetFile=None,
def main(argv=None): def main(argv=None):
if not argv: if not argv:
argv = sys.argv argv = sys.argv
args = parseArguments(argv) args, config = parseArguments(argv)
setup_logging(args, __version__) setup_logging(args, __version__)
ignore = should_ignore(args.targetFile, args.ignore) ignore = should_ignore(args.targetFile, args.ignore)
if ignore is not False: if ignore is not False:
@ -243,7 +254,7 @@ def main(argv=None):
branch = None branch = None
name = None name = None
stats = get_file_stats(args.targetFile) stats = get_file_stats(args.targetFile)
project = find_project(args.targetFile) project = find_project(args.targetFile, config)
if project: if project:
branch = project.branch() branch = project.branch()
name = project.name() name = project.name()

View file

@ -13,6 +13,7 @@ import logging
import os import os
from .projects.wakatime import WakaTime from .projects.wakatime import WakaTime
from .projects.projectmap import ProjectMap
from .projects.git import Git from .projects.git import Git
from .projects.mercurial import Mercurial from .projects.mercurial import Mercurial
from .projects.subversion import Subversion from .projects.subversion import Subversion
@ -22,15 +23,21 @@ log = logging.getLogger(__name__)
PLUGINS = [ PLUGINS = [
WakaTime, WakaTime,
ProjectMap,
Git, Git,
Mercurial, Mercurial,
Subversion, Subversion,
] ]
def find_project(path): def find_project(path, config):
for plugin in PLUGINS: for plugin in PLUGINS:
project = plugin(path) plugin_name = plugin.__name__.lower()
if config.has_section(plugin_name):
plugin_config = config
else:
plugin_config = None
project = plugin(path, plugin_config)
if project.process(): if project.process():
return project return project
return None return None

View file

@ -22,8 +22,9 @@ class BaseProject(object):
be found for the current path. be found for the current path.
""" """
def __init__(self, path): def __init__(self, path, settings):
self.path = path self.path = path
self.settings = settings
def type(self): def type(self):
""" Returns None if this is the base class. """ Returns None if this is the base class.

View file

@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
"""
wakatime.projects.projectmap
~~~~~~~~~~~~~~~~~~~~~~~~~~
Information from ~/.waka-projectmap mapping folders (relative to home folder)
to project names
:author: 3onyc
:license: BSD, see LICENSE for more details.
"""
import logging
import os
from functools import partial
from ..packages import simplejson as json
from .base import BaseProject
log = logging.getLogger(__name__)
class ProjectMap(BaseProject):
def process(self):
if not self.settings:
return False
self.project = self._find_project()
return self.project != None
def _find_project(self):
has_option = partial(self.settings.has_option, 'projectmap')
get_option = partial(self.settings.get, 'projectmap')
paths = self._path_generator()
projects = map(get_option, filter(has_option, paths))
return projects[0] if projects else None
def branch(self):
return None
def name(self):
return self.project
def _path_generator(self):
"""
Generates paths from the current directory up to the user's home folder
stripping anything in the path before the home path
"""
path = self.path.replace(os.environ['HOME'], '')
while path != os.path.dirname(path):
yield path
path = os.path.dirname(path)