support bool or list for hide_project_names config

This commit is contained in:
Alan Hamlett 2018-07-18 09:28:23 -07:00
parent 71d5eef12a
commit ae2ac14a9f
13 changed files with 78 additions and 44 deletions

View file

@ -60,7 +60,7 @@ format. An example config file with all available options::
[settings] [settings]
debug = false debug = false
api_key = your-api-key api_key = your-api-key
hide_filenames = false hide_file_names = false
hide_project_names = false hide_project_names = false
exclude = exclude =
^COMMIT_EDITMSG$ ^COMMIT_EDITMSG$

View file

@ -1,6 +1,6 @@
[settings] [settings]
debug = false debug = false
api_key = 033c47c9-0441-4eb5-8b3f-b51f27b31049 api_key = 033c47c9-0441-4eb5-8b3f-b51f27b31049
hide_filenames = hide_file_names =
missingfile missingfile
python\.py$ python\.py$

View file

@ -1,4 +1,4 @@
[settings] [settings]
debug = false debug = false
api_key = 033c47c9-0441-4eb5-8b3f-b51f27b31049 api_key = 033c47c9-0441-4eb5-8b3f-b51f27b31049
hide_filenames = invalid(regex hide_file_names = invalid(regex

View file

@ -12,4 +12,4 @@ include =
\(invalid regex) \(invalid regex)
includeme includeme
offline = true offline = true
hide_filenames = true hide_file_names = true

View file

@ -3,7 +3,7 @@ usage: wakatime [-h] [--entity FILE] [--key KEY] [--write] [--plugin PLUGIN]
[--entity-type ENTITY_TYPE] [--category CATEGORY] [--entity-type ENTITY_TYPE] [--category CATEGORY]
[--proxy PROXY] [--no-ssl-verify] [--project PROJECT] [--proxy PROXY] [--no-ssl-verify] [--project PROJECT]
[--alternate-project ALTERNATE_PROJECT] [--language LANGUAGE] [--alternate-project ALTERNATE_PROJECT] [--language LANGUAGE]
[--hostname HOSTNAME] [--disable-offline] [--hide-filenames] [--hostname HOSTNAME] [--disable-offline] [--hide-file-names]
[--hide-project-names] [--exclude EXCLUDE] [--hide-project-names] [--exclude EXCLUDE]
[--exclude-unknown-project] [--include INCLUDE] [--exclude-unknown-project] [--include INCLUDE]
[--include-only-with-project-file] [--extra-heartbeats] [--include-only-with-project-file] [--extra-heartbeats]

View file

@ -3,7 +3,7 @@ usage: wakatime [-h] [--entity FILE] [--key KEY] [--write] [--plugin PLUGIN]
[--entity-type ENTITY_TYPE] [--category CATEGORY] [--entity-type ENTITY_TYPE] [--category CATEGORY]
[--proxy PROXY] [--no-ssl-verify] [--project PROJECT] [--proxy PROXY] [--no-ssl-verify] [--project PROJECT]
[--alternate-project ALTERNATE_PROJECT] [--language LANGUAGE] [--alternate-project ALTERNATE_PROJECT] [--language LANGUAGE]
[--hostname HOSTNAME] [--disable-offline] [--hide-filenames] [--hostname HOSTNAME] [--disable-offline] [--hide-file-names]
[--hide-project-names] [--exclude EXCLUDE] [--hide-project-names] [--exclude EXCLUDE]
[--exclude-unknown-project] [--include INCLUDE] [--exclude-unknown-project] [--include INCLUDE]
[--include-only-with-project-file] [--extra-heartbeats] [--include-only-with-project-file] [--extra-heartbeats]

View file

@ -3,7 +3,7 @@ usage: wakatime [-h] [--entity FILE] [--key KEY] [--write] [--plugin PLUGIN]
[--entity-type ENTITY_TYPE] [--category CATEGORY] [--entity-type ENTITY_TYPE] [--category CATEGORY]
[--proxy PROXY] [--no-ssl-verify] [--project PROJECT] [--proxy PROXY] [--no-ssl-verify] [--project PROJECT]
[--alternate-project ALTERNATE_PROJECT] [--language LANGUAGE] [--alternate-project ALTERNATE_PROJECT] [--language LANGUAGE]
[--hostname HOSTNAME] [--disable-offline] [--hide-filenames] [--hostname HOSTNAME] [--disable-offline] [--hide-file-names]
[--hide-project-names] [--exclude EXCLUDE] [--hide-project-names] [--exclude EXCLUDE]
[--exclude-unknown-project] [--include INCLUDE] [--exclude-unknown-project] [--include INCLUDE]
[--include-only-with-project-file] [--extra-heartbeats] [--include-only-with-project-file] [--extra-heartbeats]

View file

@ -3,7 +3,7 @@ usage: wakatime [-h] [--entity FILE] [--key KEY] [--write] [--plugin PLUGIN]
[--entity-type ENTITY_TYPE] [--category CATEGORY] [--entity-type ENTITY_TYPE] [--category CATEGORY]
[--proxy PROXY] [--no-ssl-verify] [--project PROJECT] [--proxy PROXY] [--no-ssl-verify] [--project PROJECT]
[--alternate-project ALTERNATE_PROJECT] [--language LANGUAGE] [--alternate-project ALTERNATE_PROJECT] [--language LANGUAGE]
[--hostname HOSTNAME] [--disable-offline] [--hide-filenames] [--hostname HOSTNAME] [--disable-offline] [--hide-file-names]
[--hide-project-names] [--exclude EXCLUDE] [--hide-project-names] [--exclude EXCLUDE]
[--exclude-unknown-project] [--include INCLUDE] [--exclude-unknown-project] [--include INCLUDE]
[--include-only-with-project-file] [--extra-heartbeats] [--include-only-with-project-file] [--extra-heartbeats]
@ -49,7 +49,7 @@ optional arguments:
--hostname HOSTNAME Hostname of current machine. --hostname HOSTNAME Hostname of current machine.
--disable-offline Disables offline time logging instead of queuing --disable-offline Disables offline time logging instead of queuing
logged time. logged time.
--hide-filenames Obfuscate filenames. Will not send file names to api. --hide-file-names Obfuscate filenames. Will not send file names to api.
--hide-project-names Obfuscate project names. When a project folder is --hide-project-names Obfuscate project names. When a project folder is
detected instead of using the folder name as the detected instead of using the folder name as the
project, a .wakatime-project file is created with a project, a .wakatime-project file is created with a

View file

@ -414,7 +414,7 @@ class ConfigsTestCase(TestCase):
self.assertSessionCacheSaved() self.assertSessionCacheSaved()
@log_capture() @log_capture()
def test_does_not_hide_filenames_from_invalid_regex(self, logs): def test_does_not_hide_file_names_from_invalid_regex(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
@ -434,9 +434,9 @@ class ConfigsTestCase(TestCase):
self.assertNothingPrinted() self.assertNothingPrinted()
actual = self.getLogOutput(logs) actual = self.getLogOutput(logs)
expected = u('WakaTime WARNING Regex error (unbalanced parenthesis) for include pattern: invalid(regex') expected = u('WakaTime WARNING Regex error (unbalanced parenthesis) for hide_file_names pattern: invalid(regex')
if self.isPy35OrNewer: if self.isPy35OrNewer:
expected = 'WakaTime WARNING Regex error (missing ), unterminated subpattern at position 7) for include pattern: invalid(regex' expected = 'WakaTime WARNING Regex error (missing ), unterminated subpattern at position 7) for hide_file_names pattern: invalid(regex'
self.assertEquals(expected, actual) self.assertEquals(expected, actual)
heartbeat = { heartbeat = {

View file

@ -17,7 +17,8 @@ class HeartbeatTestCase(TestCase):
class Args(object): class Args(object):
exclude = [] exclude = []
hide_filenames = ['.*'] hide_file_names = ['.*']
hide_project_names = []
include = [] include = []
plugin = None plugin = None
include_only_with_project_file = None include_only_with_project_file = None
@ -50,7 +51,8 @@ class HeartbeatTestCase(TestCase):
class Args(object): class Args(object):
exclude = [] exclude = []
hide_filenames = [] hide_file_names = []
hide_project_names = []
include = [] include = []
plugin = None plugin = None
include_only_with_project_file = None include_only_with_project_file = None
@ -74,7 +76,8 @@ class HeartbeatTestCase(TestCase):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
class Args(object): class Args(object):
hide_filenames = ['.*'] hide_file_names = ['.*']
hide_project_names = []
plugin = None plugin = None
branch = 'abc123' branch = 'abc123'
@ -95,7 +98,8 @@ class HeartbeatTestCase(TestCase):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
class Args(object): class Args(object):
hide_filenames = ['.*'] hide_file_names = ['.*']
hide_project_names = []
plugin = None plugin = None
branch = 'abc123' branch = 'abc123'

View file

@ -126,10 +126,13 @@ def parse_arguments():
parser.add_argument('--disableoffline', dest='offline_deprecated', parser.add_argument('--disableoffline', dest='offline_deprecated',
action='store_true', action='store_true',
help=argparse.SUPPRESS) help=argparse.SUPPRESS)
parser.add_argument('--hide-filenames', dest='hide_filenames', parser.add_argument('--hide-file-names', dest='hide_file_names',
action='store_true', action='store_true',
help='Obfuscate filenames. Will not send file names ' + help='Obfuscate filenames. Will not send file names ' +
'to api.') 'to api.')
parser.add_argument('--hide-filenames', dest='hide_filenames',
action='store_true',
help=argparse.SUPPRESS)
parser.add_argument('--hidefilenames', dest='hidefilenames', parser.add_argument('--hidefilenames', dest='hidefilenames',
action='store_true', action='store_true',
help=argparse.SUPPRESS) help=argparse.SUPPRESS)
@ -256,26 +259,8 @@ def parse_arguments():
pass pass
if not args.exclude_unknown_project and configs.has_option('settings', 'exclude_unknown_project'): if not args.exclude_unknown_project and configs.has_option('settings', 'exclude_unknown_project'):
args.exclude_unknown_project = configs.getboolean('settings', 'exclude_unknown_project') args.exclude_unknown_project = configs.getboolean('settings', 'exclude_unknown_project')
if not args.hide_filenames and args.hidefilenames: boolean_or_list('hide_file_names', args, configs, alternative_names=['hide_filenames', 'hidefilenames'])
args.hide_filenames = args.hidefilenames boolean_or_list('hide_project_names', args, configs, alternative_names=['hide_projectnames', 'hideprojectnames'])
if args.hide_filenames:
args.hide_filenames = ['.*']
else:
args.hide_filenames = []
option = None
if configs.has_option('settings', 'hidefilenames'):
option = configs.get('settings', 'hidefilenames')
if configs.has_option('settings', 'hide_filenames'):
option = configs.get('settings', 'hide_filenames')
if option is not None:
if option.strip().lower() == 'true':
args.hide_filenames = ['.*']
elif option.strip().lower() != 'false':
for pattern in option.split("\n"):
if pattern.strip() != '':
args.hide_filenames.append(pattern)
if not args.hide_project_names and configs.has_option('settings', 'hide_project_names'):
args.hide_project_names = configs.getboolean('settings', 'hide_project_names')
if args.offline_deprecated: if args.offline_deprecated:
args.offline = False args.offline = False
if args.offline and configs.has_option('settings', 'offline'): if args.offline and configs.has_option('settings', 'offline'):
@ -316,3 +301,30 @@ def parse_arguments():
print(traceback.format_exc()) print(traceback.format_exc())
return args, configs return args, configs
def boolean_or_list(config_name, args, configs, alternative_names=[]):
"""Get a boolean or list of regexes from args and configs."""
# when argument flag present, set to wildcard regex
for key in alternative_names:
if hasattr(args, key) and getattr(args, key):
setattr(args, config_name, ['.*'])
return
setattr(args, config_name, [])
option = None
alternative_names.insert(0, config_name)
for key in alternative_names:
if configs.has_option('settings', key):
option = configs.get('settings', key)
break
if option is not None:
if option.strip().lower() == 'true':
setattr(args, config_name, ['.*'])
elif option.strip().lower() != 'false':
for pattern in option.split("\n"):
if pattern.strip() != '':
getattr(args, config_name).append(pattern)

View file

@ -132,7 +132,7 @@ class Heartbeat(object):
Returns a Heartbeat. Returns a Heartbeat.
""" """
if not self.args.hide_filenames: if not self.args.hide_file_names:
return self return self
if self.entity is None: if self.entity is None:
@ -141,7 +141,7 @@ class Heartbeat(object):
if self.type != 'file': if self.type != 'file':
return self return self
for pattern in self.args.hide_filenames: for pattern in self.args.hide_file_names:
try: try:
compiled = re.compile(pattern, re.IGNORECASE) compiled = re.compile(pattern, re.IGNORECASE)
if compiled.search(self.entity): if compiled.search(self.entity):
@ -160,7 +160,7 @@ class Heartbeat(object):
return self.update(sanitized) return self.update(sanitized)
except re.error as ex: except re.error as ex:
log.warning(u('Regex error ({msg}) for include pattern: {pattern}').format( log.warning(u('Regex error ({msg}) for hide_file_names pattern: {pattern}').format(
msg=u(ex), msg=u(ex),
pattern=u(pattern), pattern=u(pattern),
)) ))

View file

@ -12,8 +12,9 @@
import os import os
import logging import logging
import random import random
import re
from .compat import open from .compat import open, u
from .projects.git import Git from .projects.git import Git
from .projects.mercurial import Mercurial from .projects.mercurial import Mercurial
from .projects.projectfile import ProjectFile from .projects.projectfile import ProjectFile
@ -65,9 +66,11 @@ def get_project_info(configs, heartbeat, data):
branch_name = project.branch() branch_name = project.branch()
break break
if project_name is None and not data.get('hide_project_names'): if project_name is None:
project_name = data.get('project') or heartbeat.args.project project_name = data.get('project') or heartbeat.args.project
hide_project = should_obfuscate_project(heartbeat)
if project_name is None or branch_name is None: if project_name is None or branch_name is None:
for plugin_cls in REV_CONTROL_PLUGINS: for plugin_cls in REV_CONTROL_PLUGINS:
@ -79,7 +82,7 @@ def get_project_info(configs, heartbeat, data):
if project.process(): if project.process():
project_name = project_name or project.name() project_name = project_name or project.name()
branch_name = branch_name or project.branch() branch_name = branch_name or project.branch()
if data.get('hide_project_names'): if hide_project:
branch_name = None branch_name = None
project_name = generate_project_name() project_name = generate_project_name()
project_file = os.path.join(project.folder(), '.wakatime-project') project_file = os.path.join(project.folder(), '.wakatime-project')
@ -90,12 +93,27 @@ def get_project_info(configs, heartbeat, data):
project_name = None project_name = None
break break
if project_name is None: if project_name is None and not hide_project:
project_name = data.get('alternate_project') or heartbeat.args.alternate_project project_name = data.get('alternate_project') or heartbeat.args.alternate_project
return project_name, branch_name return project_name, branch_name
def should_obfuscate_project(heartbeat):
"""Returns True if hide_project_names is true or the path matches one in
the list of obfuscated project paths."""
for pattern in heartbeat.args.hide_project_names:
try:
compiled = re.compile(pattern, re.IGNORECASE)
return compiled.search(heartbeat.entity)
except re.error as ex:
log.warning(u('Regex error ({msg}) for hide_project_names pattern: {pattern}').format(
msg=u(ex),
pattern=u(pattern),
))
def get_configs_for_plugin(plugin_name, configs): def get_configs_for_plugin(plugin_name, configs):
if configs and configs.has_section(plugin_name): if configs and configs.has_section(plugin_name):
return dict(configs.items(plugin_name)) return dict(configs.items(plugin_name))