Merge pull request #4 from 3onyc/feature/projectmap
Add a ProjectMap plugin
This commit is contained in:
commit
ce4d6ce3b7
4 changed files with 105 additions and 30 deletions
|
@ -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 = {
|
||||||
|
'settings' : {
|
||||||
'api_key': None,
|
'api_key': None,
|
||||||
'ignore': [],
|
'ignore': [],
|
||||||
'verbose': False,
|
'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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
56
wakatime/projects/projectmap.py
Normal file
56
wakatime/projects/projectmap.py
Normal 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)
|
Loading…
Reference in a new issue