easydoneit-cli

Easydoneit cli is a simple task manager for terminals.
git clone https://noulin.net/git/easydoneit-cli.git
Log | Files | Refs | README | LICENSE

edi.py (150556B)


      1 #! /usr/bin/env python
      2 # -*- coding: latin-1 -*-
      3 ## @package edi
      4 #  Documentation for edi module. All Easydoneit CLI commands are defined in this module.
      5 #
      6 # Copyright (C) 2014 Spartatek AB
      7 #
      8 # contact@spartatek.se
      9 # http://spartatek.se
     10 #
     11 # EASYDONEIT CLI is free software: you can redistribute it and/or modify
     12 # it under the terms of the GNU Genereric Public License as published by
     13 # the Free Software Foundation, either version 3 of the License, or
     14 # (at your option) any later version.
     15 #
     16 # EASYDONIT CLI is distributed in the hope that it will be usesul,
     17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     19 # GNU Genereral Public License for more details.
     20 #
     21 # You should have received a copy of the GNU General Public License
     22 # along with this program. If not, see
     23 # GNU licences http://www.gnu.org/licenses
     24 
     25 import sys
     26 import re
     27 import shutil
     28 import os
     29 import ConfigParser
     30 # 0 disable, 1 enable print
     31 #:print_command_map=0
     32 #:profiler=0
     33 
     34 #:profiler
     35 #:end
     36 
     37 from edi_core import *
     38 # Import to access data_location in edi_core
     39 import edi_core
     40 
     41 ## functions to print results from list_tree/list_group
     42 #  @ingroup EDI_CLI
     43 def empty_line(tid,s):
     44 	return ''
     45 
     46 ## functions to print results from list_tree/list_group
     47 #  @ingroup EDI_CLI
     48 def print_list(task_array):
     49 	Functions = {'head group': generate_group_string_with_tid,'element': generate_task_string_with_tid}
     50 	for t in task_array:
     51 		print Functions.get(t['head'],empty_line)(t['tid'], '%3d - %s %s'%(t['position'],t['group'],t['title']))
     52 
     53 #--------------------------------------------
     54 # COMMAND LINE INTERFACE
     55 
     56 ## Default Function.
     57 #  @ingroup EDI_CLI
     58 def Nothing():
     59         print 'Command not available'
     60 
     61 ## add command name to COMMANDS, help to HELP_STRING and corresponding python functions to FUNCTIONS below
     62 COMMANDS     = ['help','version','cr','lsid','add','cat','mkdir','show','rm','vi','order','set','reset','search','mv','cp','ln','path','tree','ls','stfi','data','html','select','default','cpb','mvb','fc','bc','createDatabase','topbot','in','re','st','zip','autolink','cv','user','email','stats','many','demo','list','merge','media','at']
     63 
     64 ## ls help for both edi lsid and edi ls
     65 LS_HELP ='''edi lsid [-R|-G|-s|-L|-La|-Lx|-t] [group|task] [position]
     66 	list tasks in a group. Outside tree folder, without parameter list all tasks and groups,
     67 	with parameter list group or task title (selected with task id or group id and position),
     68 	with -R list group recursively, with position print task title.
     69 	In tree folder, without parameter list group,
     70 	with -G and when cwd is in tree, list group path with ids and titles (group1/group2...),
     71 	with task id parameter print tree path and title,
     72 	-s for sorted list by status,
     73 	-L list tasks in any group from groups in edi list (or),
     74 	-La list tasks in all groups in edi list (and),
     75 	-Lx list tasks in all groups in edi list exclusively (strictly and)
     76 	-t sort by date from oldest to newest task'''
     77 
     78 ## help command displays these strings
     79 HELP_STRINGS = ['''edi help [command]
     80 	print cli commands and data location, command parameter is optional''',
     81                 'print current version',
     82                 '''edi cr [group]
     83 	create task and open text editor, calls without parameters create task in root group,
     84 	when in tree and without parameter, create task in current group,
     85 	when group parameter is provided create task in group''',
     86 		LS_HELP,
     87 		'''edi add [-F|-t] [group] text_filename|text
     88 	add task from file. Without parameter add task in root group,
     89 	when in tree and without parameter, add task in current group,
     90 	add_task option (-F) text_filename adds task with filename in fist line of description in root group,
     91 	add_task option (-F) group text_filename adds task with filename in first line of description in group,
     92 	add_task group text_filename adds task in group
     93 	edi add -t [group] 'text' creates a task with description text''',
     94 		'''edi cat group|task|position [position]
     95 	print description. With position parameter print description for task at given position,
     96 	when in tree and without group parameter, print description at given position in current group''',
     97 		'''edi mkdir task|position
     98 	convert task to group
     99 	when in tree, convert task at given position''',
    100 		'''edi show task|position
    101 	print group title for task''',
    102 		'''edi rm task|group|position [task]
    103 	delete task or group
    104 	with group and task parameters, delete task and keep linked tasks
    105 	edi rm root deletes all tasks in default database''',
    106 		'''edi vi task|group|position [position]
    107 	edit description,
    108 	in tree, edit task or group at given position in current group''',
    109 		'''edi order [group] at_position to_position
    110 	change order in group. Without group parameter change order in root group,
    111 	in tree change order in current group''',
    112 		'''edi set task|group|position int_status
    113 	set status to int parameter,
    114 	int_status values are:
    115 %s'''%'\n'.join(['	%d: %s'%(i,j.strip()) for i,j in enumerate(TASK_STATUS)]),
    116 		'''edi reset group
    117 	set tasks in group to active. Without parameter set tasks in root group''',
    118 		'''edi search string
    119 	search string in tasks folder,
    120 	in tree, searches in current group''',
    121 		'''edi mv group task|group group
    122 	edi mv position group
    123 	move task or group,
    124 	move task or group from group parameter 1 to group parameter 3''',
    125 		'''edi cp [-E] task|group|position group|path
    126 	copy task to a group,
    127 	option -E copy description to path, first line in description is filename''',
    128 		'''edi ln task|position group
    129 	add a reference in group''',
    130 		'''edi path task|group|position
    131 	print task filesystem path''',
    132 		'''edi tree
    133 	print tree path''',
    134 		LS_HELP.replace('edi lsid ','edi ls ').replace('list tasks in a group','ls groups and tasks with positions only'),
    135 		'''edi stfi status_filter state
    136 	enable/disable (set) status filter,
    137 	without parameters, print current filters,
    138 
    139 	status_filter values are:
    140 %s
    141 
    142 	state values are:
    143 %s'''%('\n'.join(['	%s'%i.strip() for i in TASK_STATUS]), '\n'.join(['	%s'%i for i in STATUS_FILTER_STATES])),
    144 		'''edi data [-d] [database_name] [path]
    145 	set path for database and create database when it doesnt exist,
    146 	without option, print current data path
    147 	Option -d delete a database''',
    148 		'''edi html [-R|-G|-s|-L|-La|-Lx|-t] group|task [position]
    149 	generate html for tasks, same options as ls''',
    150 		'''edi select [database_name_1,database_name2...]
    151 	set selected databases
    152 	without option, print selected databases''',
    153 		'''edi default [database_name]
    154 	set default database for new tasks
    155 	without option, print default database''',
    156 		'''edi cpb task|group|position database group
    157 	copy task or group to database/group''',
    158 		'''edi mvb group task|group database group
    159 	edi mvb position database group
    160 	move task or group to database/group''',
    161 		'''edi fc task|group|position [color]
    162 	set/get forground color from task or group
    163 	color is 4 decimal numbers seperated with commas
    164 	0,0,0,255''',
    165 		'''edi bc task|group|position [color]
    166 	set/get background color from task or group
    167 	color is 4 decimal numbers seperated with commas
    168 	0,0,0,255''',
    169 		'''edi createDatabase database_name path
    170 	create database folders and set path
    171 	this command creates the path when it doesnt exist''',
    172 		'''edi topbot [top|bottom]
    173 	select add new tasks in bottom of group or on top of group
    174 	Default is bottom
    175 	without parameter, print status''',
    176 		'''edi in [-A] group|position
    177 	print group tasks in md format
    178 	when in tree, print group at given position
    179 	option -A create an agenda after title for slideshows''',
    180 		'''edi re [-A] group|position
    181 	print group tasks in reStructuredText format
    182 	when in tree, print group at given position
    183 	option -A create an agenda after title for slideshows''',
    184 		'''edi st
    185 	shows trees for selected databases, print all trees: group tids and titles''',
    186 		'''edi zip database_name [path]
    187 	creates an archive of the database in database_name.tar.bz2 in path or current folder''',
    188 		'''edi autolink [group1,group2...]
    189 	set configuration for linking new tasks to autolink groups
    190 	without option, print autolink group list''',
    191 		'''edi cv group|pos
    192 	convert empty group to task''',
    193 		'''edi user [First name Last name]
    194 	set user name
    195 	without parameter, display username''',
    196 		'''edi email [user email]
    197 	set user email
    198 	without parameter, display user email''',
    199 		'''edi stats [group]
    200 	show statistics
    201 	without parameter, show statistics in selected databases or current group in tree''',
    202 		'''edi many [-1|-g] [group] text_file
    203 	add many tasks from a file, tasks are seperated with '---' lines
    204 	with -1, add one task per line from a file,
    205 	with -g, create a group per line from file, one space for deeper levels''',
    206 		'''edi demo
    207 	display commands to show how to use Easydoneit CLI''',
    208 		'''edi list group1,group2...
    209 	set a list of groups for edi ls -L,-La and -Lx options
    210 	the groups have to be in the same database
    211 	without parameter, list groups''',
    212 		'''edi merge [path|database_name] database_name_2
    213 	copy tasks from database_name to database_name_2 with no changes
    214 	WARNING - the source database is merged correctly several times when the tree remains the same since the first merge.''',
    215 		'''edi media [task|pos] [image file|sound file]
    216 	copy media file to task. Only one media file per task is allowed, for more attachments use edi at
    217 	without parameter, show media type''',
    218 		'''edi at [task|pos] [filename|*]
    219 	copy file to task as attachments.
    220 	without parameter, show attachment files''']
    221 
    222 HELP          = zip(COMMANDS,HELP_STRINGS)
    223 HELP_DICT     = dict(HELP)
    224 
    225 ## print cli commands and data location
    226 #
    227 #  print format:<br>
    228 #  command<br>
    229 #  TAB help string
    230 #  @ingroup EDI_CLI
    231 def help():
    232 	print 'Easydoneit help'
    233 	print 'http://spartatek.se/easydoneit_cli'
    234 	print
    235 #:define edi_version
    236 	f = open('%s/VERSION'%os.path.abspath(os.path.dirname(sys.argv[0])))
    237 	v = f.readline()
    238 	f.close()
    239 	print 'Version %s'%v
    240 #:end
    241 	print 'Selected data_location'
    242 	print edi_core.data_location
    243 	print
    244 	if len(sys.argv) < 3:
    245 		# print complete help
    246 		for c,h in HELP:
    247 			print c
    248 			print '	%s\n'%h
    249 
    250 	# print help for specified command
    251 	if len(sys.argv) == 3:
    252 		if not sys.argv[2] in HELP_DICT.keys():
    253 			sys.exit('%s is invalid command.'%sys.argv[2])
    254 		print sys.argv[2]
    255 		print '	%s\n'%HELP_DICT[sys.argv[2]]
    256 
    257 
    258 ## print current version
    259 #  @ingroup EDI_CLI
    260 def version():
    261 #:edi_version
    262 	f = open('%s/VERSION'%os.path.abspath(os.path.dirname(sys.argv[0])))
    263 	v = f.readline()
    264 	f.close()
    265 	print 'Version %s'%v
    266 
    267 ## create task and open text editor, calls without parameters create task in root group, when group parameter is provided create task in group
    268 #  @ingroup EDI_CLI
    269 def create_task_cli():
    270 	# Select group and database
    271 
    272 #:define figure_out_if_in_tree
    273 	status        = ''
    274 	cwd           = os.path.realpath(os.getcwd())
    275 	#loop_on_selected_databases
    276 	z             = zip(edi_core.selected, edi_core.selected_path)
    277 	for d,path in z:
    278 		edi_core.data_location        = os.path.expanduser(path)
    279 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    280 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    281 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    282 
    283 		# check path from left
    284 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
    285 		if real_tree_path == cwd[:len(real_tree_path)]:
    286 			status = 'in tree'
    287 			p_l    = edi_core.data_location_tree.split('/')[-2:]
    288 			break
    289 #:end
    290 
    291 	# Initialize group in case len(sys.argv) != 2
    292 	group = ''
    293 	if len(sys.argv) == 2:
    294 		# no parameter - just command
    295 		# select current group when in tree
    296 		if status == 'in tree':
    297 			#get_current_group_in_tree
    298 			if cwd.split('/')[-1] == 'tree':
    299 				group = 'root'
    300 			else:
    301 				group = cwd.split('/')[-1]
    302 			#end
    303 		else:
    304 			# default group
    305 			group = 'root'
    306 
    307 	if (len(sys.argv) == 2) and (group == 'root') and (not status):
    308 		# set default database when group is root and cwd not in tree
    309 #:define set_default_database
    310 		z = dict(zip(edi_core.selected, edi_core.selected_path))
    311 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
    312 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    313 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    314 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    315 		if not os.path.exists(edi_core.data_location):
    316 			sys.exit('%s is unreachable.'%edi_core.data_location)
    317 #:end
    318 	if len(sys.argv) >= 3:
    319 		group = sys.argv[2]
    320 
    321 	if (group != 'root') and ((not status) or (len(sys.argv) == 3)):
    322 		# find group in selected databases and setup data_location when not in tree or group is parameter
    323 #:define find_group_in_selected_databases_and_setup_data_location
    324 		for path in edi_core.selected_path:
    325 			edi_core.data_location        = os.path.expanduser(path)
    326 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    327 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    328 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    329 
    330 			if not os.path.exists(edi_core.data_location):
    331 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
    332 			groups = os.listdir(edi_core.data_location_groups)
    333 			if group in groups:
    334 				break
    335 #:end
    336 	# Verify parameter
    337 	if not is_this_task_a_group(group):
    338 		sys.exit('%s is not a group.'%group)
    339 	print create_task(group)
    340 
    341 ## list tasks in a group. Outside tree folder, without parameter list all tasks and groups, with parameter list group or task title, with -R list group recursively, with position print task title. In tree folder, without parameter list group, with -G list group path with ids and titles, with task id parameter print tree path and title
    342 #  @ingroup EDI_CLI
    343 def ls_generic():
    344 	# Figure out if the command is run in the tree
    345 #:figure_out_if_in_tree
    346 	status        = ''
    347 	cwd           = os.path.realpath(os.getcwd())
    348 	#loop_on_selected_databases
    349 	z             = zip(edi_core.selected, edi_core.selected_path)
    350 	for d,path in z:
    351 		edi_core.data_location        = os.path.expanduser(path)
    352 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    353 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    354 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    355 
    356 		# check path from left
    357 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
    358 		if real_tree_path == cwd[:len(real_tree_path)]:
    359 			status = 'in tree'
    360 			p_l    = edi_core.data_location_tree.split('/')[-2:]
    361 			break
    362 
    363 	# Decide what to execute
    364 	if len(sys.argv) == 2:
    365 		if status:
    366 			exe = 'ls in tree'
    367 		else:
    368 			exe = 'ls root'
    369 	else:
    370 		if (sys.argv[2] == '-R') or (sys.argv[2] == '-G') or (sys.argv[2] == '-s') or (sys.argv[2] == '-t'):
    371 			if len(sys.argv) == 4:
    372 				# there is a task id parameter, use that instead of tree location
    373 				tid    = sys.argv[3]
    374 				status = ''
    375 			else:
    376 				tid = 'root'
    377 		else:
    378 			tid = sys.argv[2]
    379 
    380 		if status:
    381 			# in tree, set tid to cwd
    382 			tid = cwd.split('/')[-1]
    383 
    384 #:define find_task_in_selected_databases_and_setup_data_location
    385 		if tid == 'root':
    386 			#set_default_database
    387 			z = dict(zip(edi_core.selected, edi_core.selected_path))
    388 			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
    389 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    390 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    391 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    392 			if not os.path.exists(edi_core.data_location):
    393 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
    394 		elif tid != 'tree':
    395 			for path in edi_core.selected_path:
    396 				edi_core.data_location        = os.path.expanduser(path)
    397 				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    398 				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    399 				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    400 
    401 				if not os.path.exists(edi_core.data_location):
    402 					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
    403 				tasks = os.listdir(edi_core.data_location_tasks)
    404 				if tid in tasks:
    405 					break
    406 #:end
    407 		if is_this_task_a_group(sys.argv[2]):
    408 			if len(sys.argv) == 3:
    409 				exe = 'ls group'
    410 			else:
    411 				exe = 'ls at position'
    412 		elif sys.argv[2] == '-R':
    413 			if (is_this_task_a_group(tid)) or (tid == 'tree'):
    414 				exe = 'ls tree'
    415 				# tid is tree when cwd is at root, change to root for ls -R.
    416 				if tid == 'tree':
    417 					tid = 'root'
    418 			else:
    419 				exe = 'ls task'
    420 				# replace -R option with tid and run regular ls task
    421 				sys.argv[2] = tid
    422 		elif sys.argv[2] == '-s':
    423 			exe = 'ls sort'
    424 			# tid is tree when cwd is at root, change to root for ls -s.
    425 			if tid == 'tree':
    426 				tid = 'root'
    427 		elif sys.argv[2] == '-t':
    428 			exe = 'ls sort by date'
    429 			# tid is tree when cwd is at root, change to root for ls -t.
    430 			if tid == 'tree':
    431 				tid = 'root'
    432 		elif sys.argv[2] == '-L':
    433 			exe = 'ls any selected groups'
    434 		elif sys.argv[2] == '-La':
    435 			exe = 'ls all in selected groups'
    436 		elif sys.argv[2] == '-Lx':
    437 			exe = 'ls all in selected groups exclusively'
    438 		elif sys.argv[2] == '-G' and status:
    439 			exe = 'ls groups in tree path'
    440 		else:
    441 			exe         = 'ls task'
    442 			if sys.argv[2] == '-G':
    443 				if len(sys.argv) < 4:
    444 					exe = 'ls root'
    445 				else:
    446 					# replace -G option with tid and run regular ls task
    447 					sys.argv[2] = sys.argv[3]
    448 
    449 	if exe == 'ls in tree':
    450 		if cwd.split('/')[-1] == 'tree':
    451 			exe         = 'ls group root'
    452 		else:
    453 			print_list(list_group(cwd.split('/')[-1]))
    454 	if exe == 'ls root':
    455 		# print root in all selected databases
    456 #:define loop_on_selected_databases
    457 		z = zip(edi_core.selected, edi_core.selected_path)
    458 		for d,path in z:
    459 			print '%s - %s' % (d,path)
    460 			edi_core.data_location        = os.path.expanduser(path)
    461 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    462 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    463 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    464 			if not os.path.exists(edi_core.data_location):
    465 				sys.exit('%s is unreachable.'%edi_core.data_location)
    466 #:end
    467 			print_list(list_tree('root'))
    468 	if exe == 'ls group root':
    469 		print_list(list_group('root'))
    470 	if exe == 'ls group':
    471 		group = sys.argv[2]
    472 		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
    473 #:find_group_in_selected_databases_and_setup_data_location
    474 		for path in edi_core.selected_path:
    475 			edi_core.data_location        = os.path.expanduser(path)
    476 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    477 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    478 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    479 
    480 			if not os.path.exists(edi_core.data_location):
    481 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
    482 			groups = os.listdir(edi_core.data_location_groups)
    483 			if group in groups:
    484 				break
    485 		if group == 'root':
    486 			z = zip(edi_core.selected, edi_core.selected_path)
    487 			for d,path in z:
    488 				print '%s - %s' % (d,path)
    489 				edi_core.data_location        = os.path.expanduser(path)
    490 				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    491 				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    492 				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    493 
    494 				if not os.path.exists(edi_core.data_location):
    495 					sys.exit('%s is unreachable.'%edi_core.data_location)
    496 				print_list(list_group(group))
    497 		else:
    498 			print_list(list_group(group))
    499 	if exe == 'ls at position':
    500 		# Find task at given postion
    501 		group    = sys.argv[2]
    502 		try:
    503 			position = int(sys.argv[3])
    504 		except:
    505 			sys.exit('%s is invalid position'%sys.argv[3])
    506 #:define find_task_at_position
    507 		if position < 0:
    508 			sys.exit('Position %d is invalid.'%position)
    509 		group_tasks = os.listdir(generate_group_path(group))
    510 		order_id    = baseconvert(position)
    511 		tid         = ''
    512 		for t in group_tasks:
    513 			# find exact match
    514 			if order_id == t[:ORDER_ID_LENGTH]:
    515 				tid = t[ORDER_ID_LENGTH:]
    516 		if not tid:
    517 			sys.exit('Position %d does not exist.'%position)
    518 #:end
    519 		# End - Find task at given postion
    520 		print generate_task_string_with_tid(tid,get_task_title(tid))
    521 	if exe == 'ls tree':
    522 		print_list(list_tree(tid))
    523 	if exe == 'ls groups in tree path':
    524 		# p is data_location folder/tree
    525 		p = '/'.join(p_l)
    526 		# if empty then command is run in tree root
    527 		if cwd.split(p)[-1]:
    528 			# print path of tids: tid/tid...
    529 			print cwd.split(p)[-1][1:]
    530 			group_titles_in_path = []
    531 			for g in cwd.split(p)[-1][1:].split('/'):
    532 				group_titles_in_path.append(get_task_title(g))
    533 			# print title/title...
    534 			print '/'.join(group_titles_in_path)
    535 	if exe == 'ls task':
    536 		if status:
    537 			# print group path titles and task
    538 			# in tree folder
    539 			p = '/'.join(p_l)
    540 			# if empty then command is run in tree root
    541 			if cwd.split(p)[-1]:
    542 				print cwd.split(p)[-1][1:]
    543 				group_titles_in_path = []
    544 				for g in cwd.split(p)[-1][1:].split('/'):
    545 					group_titles_in_path.append(get_task_title(g))
    546 				# print title/title...
    547 				print '/'.join(group_titles_in_path)
    548 			# Verify that task sys.argv[2] is in database
    549 			tasks = os.listdir(edi_core.data_location_tasks)
    550 			if not sys.argv[2] in tasks:
    551 				sys.exit('%s not found.'%sys.argv[2])
    552 			print generate_task_string_with_tid(sys.argv[2],get_task_title(sys.argv[2]))
    553 		else:
    554 			#find_task_in_selected_databases_and_setup_data_location
    555 			tid_in_database = ''
    556 			for path in edi_core.selected_path:
    557 				edi_core.data_location        = os.path.expanduser(path)
    558 				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    559 				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    560 				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    561 
    562 				tasks = os.listdir(edi_core.data_location_tasks)
    563 				if sys.argv[2] in tasks:
    564 					tid_in_database = 'yes'
    565 					break
    566 			if not tid_in_database:
    567 				sys.exit('%s not found.'%sys.argv[2])
    568 			print generate_task_string_with_tid(sys.argv[2],get_task_title(sys.argv[2]))
    569 
    570 	if exe == 'ls sort':
    571 		if not is_this_task_a_group(tid):
    572 			sys.exit('%s is not a group.'%tid)
    573 		task_attributes = list_group(tid)
    574 		sorted_tasks    = sort_task_attributes(task_attributes)
    575 		print_list(sorted_tasks)
    576 
    577 	if exe == 'ls sort by date':
    578 		if not is_this_task_a_group(tid):
    579 			sys.exit('%s is not a group.'%tid)
    580 		task_attributes = list_group(tid)
    581 		sorted_tasks    = sort_task_attributes_by_date(task_attributes)
    582 		print_list(sorted_tasks)
    583 
    584 	if exe == 'ls any selected groups':
    585 		if not edi_core.list_of_groups:
    586 			sys.exit('List empty')
    587 
    588 		tid = edi_core.list_of_groups[0]
    589 		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
    590 #:find_task_in_selected_databases_and_setup_data_location
    591 		if tid == 'root':
    592 			#set_default_database
    593 			z = dict(zip(edi_core.selected, edi_core.selected_path))
    594 			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
    595 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    596 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    597 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    598 			if not os.path.exists(edi_core.data_location):
    599 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
    600 		elif tid != 'tree':
    601 			for path in edi_core.selected_path:
    602 				edi_core.data_location        = os.path.expanduser(path)
    603 				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    604 				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    605 				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    606 
    607 				if not os.path.exists(edi_core.data_location):
    608 					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
    609 				tasks = os.listdir(edi_core.data_location_tasks)
    610 				if tid in tasks:
    611 					break
    612 
    613 		# check that all groups are available in the database
    614 		status = 'search groups'
    615 		for g in edi_core.list_of_groups:
    616 			if not is_this_task_a_group(g):
    617 				status = 'group not found, edi cannot list all groups'
    618 		if status == 'group not found, edi cannot list all groups':
    619 			sys.exit(status)
    620 
    621 		# list tasks in all groups
    622 		task_attributes = list_group(tid)
    623 		empty_line      = task_attributes[-1]
    624 		# remove empty lines between groups
    625 		del task_attributes[-1]
    626 
    627 		# add other groups to the list
    628 		for tid in edi_core.list_of_groups[1:]:
    629 			# remove head group, keep head group only for first group in the group list
    630 			# remove empty lines between groups
    631 			task_attributes += list_group(tid)[1:-1]
    632 
    633 		# remove duplicated tasks
    634 		tasks = []
    635 		tasks.append(task_attributes[0])
    636 		# array used to prevent duplicated tasks
    637 		tids  = []
    638 		for t in task_attributes[1:]:
    639 			if not t['tid'] in tids:
    640 				tasks.append(t)
    641 				tids.append(t['tid'])
    642 
    643 		tasks.append(empty_line)
    644 		print_list(tasks)
    645 
    646 
    647 	if exe == 'ls all in selected groups':
    648 		if not edi_core.list_of_groups:
    649 			sys.exit('List empty')
    650 
    651 		tid = edi_core.list_of_groups[0]
    652 		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
    653 #:find_task_in_selected_databases_and_setup_data_location
    654 		if tid == 'root':
    655 			#set_default_database
    656 			z = dict(zip(edi_core.selected, edi_core.selected_path))
    657 			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
    658 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    659 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    660 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    661 			if not os.path.exists(edi_core.data_location):
    662 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
    663 		elif tid != 'tree':
    664 			for path in edi_core.selected_path:
    665 				edi_core.data_location        = os.path.expanduser(path)
    666 				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    667 				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    668 				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    669 
    670 				if not os.path.exists(edi_core.data_location):
    671 					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
    672 				tasks = os.listdir(edi_core.data_location_tasks)
    673 				if tid in tasks:
    674 					break
    675 
    676 		if len(edi_core.list_of_groups) == 1:
    677 			if not is_this_task_a_group(tid):
    678 				sys.exit('%s not found, edi cannot list all groups' % tid)
    679 			# only one group, regular ls
    680 			print_list(list_group(tid))
    681 			sys.exit(0)
    682 
    683 		# check that all groups are available in the database
    684 		status = 'search groups'
    685 		for g in edi_core.list_of_groups:
    686 			if not is_this_task_a_group(g):
    687 				status = 'group not found, edi cannot list all groups'
    688 		if status == 'group not found, edi cannot list all groups':
    689 			sys.exit(status)
    690 
    691 		# list tasks in all groups
    692 		task_attributes = list_group(tid)
    693 		empty_line      = task_attributes[-1]
    694 		# remove empty lines between groups
    695 		del task_attributes[-1]
    696 
    697 		# add other groups to the list
    698 		for tid in edi_core.list_of_groups[1:]:
    699 			# remove head group, keep head group only for first group in the group list
    700 			# remove empty lines between groups
    701 			task_attributes += list_group(tid)[1:-1]
    702 
    703 		# keep tasks only in all listed groups
    704 		tasks = []
    705 		tasks.append(task_attributes[0])
    706 		# array used to prevent duplicated tasks
    707 		tids  = []
    708 		for t in task_attributes[1:]:
    709 			if is_linked(t['tid']):
    710 				groups = os.listdir('%s/groups/' % generate_task_path(t['tid']))
    711 				# check that the task in all listed group
    712 				status = 'all in groups'
    713 				for g in edi_core.list_of_groups:
    714 					if not g in groups:
    715 						status = 'missing group'
    716 				if (status == 'all in groups') and (not t['tid'] in tids):
    717 					tasks.append(t)
    718 					tids.append(t['tid'])
    719 
    720 
    721 		tasks.append(empty_line)
    722 		print_list(tasks)
    723 
    724 	if exe == 'ls all in selected groups exclusively':
    725 		if not edi_core.list_of_groups:
    726 			sys.exit('List empty')
    727 
    728 		tid = edi_core.list_of_groups[0]
    729 		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
    730 #:find_task_in_selected_databases_and_setup_data_location
    731 		if tid == 'root':
    732 			#set_default_database
    733 			z = dict(zip(edi_core.selected, edi_core.selected_path))
    734 			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
    735 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    736 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    737 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    738 			if not os.path.exists(edi_core.data_location):
    739 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
    740 		elif tid != 'tree':
    741 			for path in edi_core.selected_path:
    742 				edi_core.data_location        = os.path.expanduser(path)
    743 				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    744 				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    745 				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    746 
    747 				if not os.path.exists(edi_core.data_location):
    748 					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
    749 				tasks = os.listdir(edi_core.data_location_tasks)
    750 				if tid in tasks:
    751 					break
    752 
    753 		# check that all groups are available in the database
    754 		status = 'search groups'
    755 		for g in edi_core.list_of_groups:
    756 			if not is_this_task_a_group(g):
    757 				status = 'group not found, edi cannot list all groups'
    758 		if status == 'group not found, edi cannot list all groups':
    759 			sys.exit(status)
    760 
    761 		# list tasks in all groups
    762 		task_attributes = list_group(tid)
    763 		empty_line      = task_attributes[-1]
    764 		# remove empty lines between groups
    765 		del task_attributes[-1]
    766 
    767 		# add other groups to the list
    768 		for tid in edi_core.list_of_groups[1:]:
    769 			# remove head group, keep head group only for first group in the group list
    770 			# remove empty lines between groups
    771 			task_attributes += list_group(tid)[1:-1]
    772 
    773 		# keep tasks only in all listed groups
    774 		tasks = []
    775 		tasks.append(task_attributes[0])
    776 		# array used to prevent duplicated tasks
    777 		tids  = []
    778 		for t in task_attributes[1:]:
    779 			if is_linked(t['tid']):
    780 				groups = os.listdir('%s/groups/' % generate_task_path(t['tid']))
    781 				# check that the task in all listed group exclusively
    782 				status = 'all groups in list_of_groups'
    783 				for g in groups:
    784 					if not g in edi_core.list_of_groups:
    785 						status = 'a group is not in the list'
    786 				if (status == 'all groups in list_of_groups') and (len(groups) == len(edi_core.list_of_groups)) and (not t['tid'] in tids):
    787 					tasks.append(t)
    788 					tids.append(t['tid'])
    789 
    790 
    791 		tasks.append(empty_line)
    792 		print_list(tasks)
    793 
    794 
    795 ## list with tids
    796 #  @ingroup EDI_CLI
    797 def lsid():
    798 	# list tids and positions
    799 	edi_core.list_option = 'tids'
    800 
    801 	ls_generic()
    802 
    803 # ls groups and tasks with positions
    804 #  @ingroup EDI_CLI
    805 def ls():
    806 	# list positions only
    807 	edi_core.list_option = 'positions'
    808 
    809 	ls_generic()
    810 
    811 ## add task from file. Without parameter add task in root group. add_task option (-F) text_filename add task with filename in fist line of description in root group. add_task option (-F) group text_filename add task with filename in first line of description in group. add_task group text_filename add task in group
    812 #  @ingroup EDI_CLI
    813 def add_task_cli():
    814 	if len(sys.argv) < 3:
    815 		# not enough parameters, call create_task
    816 		create_task_cli()
    817 		return
    818 
    819 #:figure_out_if_in_tree
    820 	status        = ''
    821 	cwd           = os.path.realpath(os.getcwd())
    822 	#loop_on_selected_databases
    823 	z             = zip(edi_core.selected, edi_core.selected_path)
    824 	for d,path in z:
    825 		edi_core.data_location        = os.path.expanduser(path)
    826 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    827 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    828 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    829 
    830 		# check path from left
    831 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
    832 		if real_tree_path == cwd[:len(real_tree_path)]:
    833 			status = 'in tree'
    834 			p_l    = edi_core.data_location_tree.split('/')[-2:]
    835 			break
    836 
    837 	options                = ''
    838 	group_parameter_status = 'group is a command line parameter'
    839 	if len(sys.argv) < 4:
    840 		# Parameters are: command filename
    841 		# select current group when in tree
    842 		if status == 'in tree':
    843 			#get_current_group_in_tree
    844 			if cwd.split('/')[-1] == 'tree':
    845 				group = 'root'
    846 			else:
    847 				group = cwd.split('/')[-1]
    848 			#end
    849 		else:
    850 			# default group
    851 			group = 'root'
    852 		group_parameter_status = 'edi selected group'
    853 
    854 		text_file = sys.argv[2]
    855 	else:
    856 		if ((sys.argv[2] == '-F') or (sys.argv[2] == '-t')) and len(sys.argv) == 4:
    857 			options   = sys.argv[2]
    858 			text_file = sys.argv[3]
    859 			# select current group when in tree
    860 			if status == 'in tree':
    861 				#get_current_group_in_tree
    862 				if cwd.split('/')[-1] == 'tree':
    863 					group = 'root'
    864 				else:
    865 					group = cwd.split('/')[-1]
    866 				#end
    867 			else:
    868 				# default group
    869 				group = 'root'
    870 			group_parameter_status = 'edi selected group'
    871 		if ((sys.argv[2] == '-F') or (sys.argv[2] == '-t')) and len(sys.argv) == 5:
    872 			options   = sys.argv[2]
    873 			group     = sys.argv[3]
    874 			text_file = sys.argv[4]
    875 		if ((sys.argv[2] != '-F') and (sys.argv[2] != '-t')):
    876 			group     = sys.argv[2]
    877 			text_file = sys.argv[3]
    878 	if not options:
    879 		exe = 'add'
    880 	else:
    881 		if options == '-F':
    882 			# option -F stores text_file filename in first line of description
    883 			exe = 'add task and filename'
    884 		elif options == '-t':
    885 			# option -F stores text_file filename in first line of description
    886 			exe = 'add text from command line'
    887 
    888 	if (group == 'root') and (not status):
    889 		# set default database when group is root and cwd not in tree
    890 #:set_default_database
    891 		z = dict(zip(edi_core.selected, edi_core.selected_path))
    892 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
    893 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    894 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    895 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    896 		if not os.path.exists(edi_core.data_location):
    897 			sys.exit('%s is unreachable.'%edi_core.data_location)
    898 	if (group != 'root') and ((not status) or (group_parameter_status == 'group is a command line parameter')):
    899 #:find_group_in_selected_databases_and_setup_data_location
    900 		for path in edi_core.selected_path:
    901 			edi_core.data_location        = os.path.expanduser(path)
    902 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    903 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    904 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    905 
    906 			if not os.path.exists(edi_core.data_location):
    907 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
    908 			groups = os.listdir(edi_core.data_location_groups)
    909 			if group in groups:
    910 				break
    911 
    912 	if not is_this_task_a_group(group):
    913 		sys.exit('%s is not a group.'%group)
    914 
    915 	if exe == 'add':
    916 		if not os.path.exists(text_file):
    917 			sys.exit('%s not accessible.'%text_file)
    918 		print add_task(group,text_file)
    919 	if exe == 'add task and filename':
    920 		if not os.path.exists(text_file):
    921 			sys.exit('%s not accessible.'%text_file)
    922 		print add_task_and_filename(group,text_file)
    923 	if exe == 'add text from command line':
    924 		print add_text(group,text_file)
    925 
    926 ## print description. With position parameter print description for task at given position
    927 #  @ingroup EDI_CLI
    928 def cat():
    929 	if len(sys.argv) < 3:
    930 		sys.exit('Too little parameters.')
    931 	tid = sys.argv[2]
    932 
    933 	# Figure out if the command is run in the tree
    934 #:figure_out_if_in_tree
    935 	status        = ''
    936 	cwd           = os.path.realpath(os.getcwd())
    937 	#loop_on_selected_databases
    938 	z             = zip(edi_core.selected, edi_core.selected_path)
    939 	for d,path in z:
    940 		edi_core.data_location        = os.path.expanduser(path)
    941 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    942 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    943 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    944 
    945 		# check path from left
    946 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
    947 		if real_tree_path == cwd[:len(real_tree_path)]:
    948 			status = 'in tree'
    949 			p_l    = edi_core.data_location_tree.split('/')[-2:]
    950 			break
    951 
    952 #:define find_task_sysargv2_in_selected_databases
    953 	# the goal for this code is to reset status when a tid is an existing task
    954 	# when parameter is taskid, it doesnt matter if cwd is in tree
    955 	# find task in selected databases
    956 	for path in edi_core.selected_path:
    957 		data_location        = os.path.expanduser(path)
    958 		data_location_tasks  = '%s/tasks'%data_location
    959 
    960 		if not os.path.exists(data_location):
    961 			sys.exit('%s is unreachable.'%path)
    962 		tasks = os.listdir(data_location_tasks)
    963 		if sys.argv[2] in tasks:
    964 			# found task, setup database below
    965 			status = ''
    966 			break
    967 #:end
    968 
    969 	if status == 'in tree':
    970 #:define get_current_group_in_tree
    971 		if cwd.split('/')[-1] == 'tree':
    972 			group = 'root'
    973 		else:
    974 			group = cwd.split('/')[-1]
    975 #:end
    976 
    977 	if (len(sys.argv) == 3) and (not status):
    978 		# group parameter and not in tree
    979 		tid = sys.argv[2]
    980 		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
    981 #:find_task_in_selected_databases_and_setup_data_location
    982 		if tid == 'root':
    983 			#set_default_database
    984 			z = dict(zip(edi_core.selected, edi_core.selected_path))
    985 			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
    986 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    987 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    988 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    989 			if not os.path.exists(edi_core.data_location):
    990 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
    991 		elif tid != 'tree':
    992 			for path in edi_core.selected_path:
    993 				edi_core.data_location        = os.path.expanduser(path)
    994 				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
    995 				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
    996 				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
    997 
    998 				if not os.path.exists(edi_core.data_location):
    999 					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   1000 				tasks = os.listdir(edi_core.data_location_tasks)
   1001 				if tid in tasks:
   1002 					break
   1003 
   1004 	if (len(sys.argv) == 3) and (status == 'in tree'):
   1005 		# Find task at given postion
   1006 #:define get_position_from_argv2
   1007 		try:
   1008 			position    = int(sys.argv[2])
   1009 		except:
   1010 			sys.exit('%s is invalid position'%sys.argv[2])
   1011 #:end
   1012 #:find_task_at_position
   1013 		if position < 0:
   1014 			sys.exit('Position %d is invalid.'%position)
   1015 		group_tasks = os.listdir(generate_group_path(group))
   1016 		order_id    = baseconvert(position)
   1017 		tid         = ''
   1018 		for t in group_tasks:
   1019 			# find exact match
   1020 			if order_id == t[:ORDER_ID_LENGTH]:
   1021 				tid = t[ORDER_ID_LENGTH:]
   1022 		if not tid:
   1023 			sys.exit('Position %d does not exist.'%position)
   1024 
   1025 	if len(sys.argv) == 4:
   1026 		group    = sys.argv[2]
   1027 		try:
   1028 			position = int(sys.argv[3])
   1029 		except:
   1030 			sys.exit('%s is invalid position'%sys.argv[3])
   1031 		# find_task_in_selected_databases_and_setup_data_location needs tid, here tid = group
   1032 		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   1033 #:find_task_in_selected_databases_and_setup_data_location
   1034 		if tid == 'root':
   1035 			#set_default_database
   1036 			z = dict(zip(edi_core.selected, edi_core.selected_path))
   1037 			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   1038 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1039 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1040 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1041 			if not os.path.exists(edi_core.data_location):
   1042 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   1043 		elif tid != 'tree':
   1044 			for path in edi_core.selected_path:
   1045 				edi_core.data_location        = os.path.expanduser(path)
   1046 				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1047 				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1048 				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1049 
   1050 				if not os.path.exists(edi_core.data_location):
   1051 					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   1052 				tasks = os.listdir(edi_core.data_location_tasks)
   1053 				if tid in tasks:
   1054 					break
   1055 		if not is_this_task_a_group(group):
   1056 			sys.exit('%s is not a group.'%group)
   1057 #:find_task_at_position
   1058 		if position < 0:
   1059 			sys.exit('Position %d is invalid.'%position)
   1060 		group_tasks = os.listdir(generate_group_path(group))
   1061 		order_id    = baseconvert(position)
   1062 		tid         = ''
   1063 		for t in group_tasks:
   1064 			# find exact match
   1065 			if order_id == t[:ORDER_ID_LENGTH]:
   1066 				tid = t[ORDER_ID_LENGTH:]
   1067 		if not tid:
   1068 			sys.exit('Position %d does not exist.'%position)
   1069 
   1070 	# Verify that task tid is in database
   1071 	tasks = os.listdir(edi_core.data_location_tasks)
   1072 	if not tid in tasks:
   1073 		sys.exit('%s not found.'%tid)
   1074 	print ''.join(display_task(tid))
   1075 
   1076 ## convert task to group
   1077 #  @ingroup EDI_CLI
   1078 def mkdir():
   1079 	if len(sys.argv) < 3:
   1080 		sys.exit('Too little parameters.')
   1081 	# Figure out if the command is run in the tree
   1082 #:figure_out_if_in_tree
   1083 	status        = ''
   1084 	cwd           = os.path.realpath(os.getcwd())
   1085 	#loop_on_selected_databases
   1086 	z             = zip(edi_core.selected, edi_core.selected_path)
   1087 	for d,path in z:
   1088 		edi_core.data_location        = os.path.expanduser(path)
   1089 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1090 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1091 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1092 
   1093 		# check path from left
   1094 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   1095 		if real_tree_path == cwd[:len(real_tree_path)]:
   1096 			status = 'in tree'
   1097 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   1098 			break
   1099 
   1100 #:find_task_sysargv2_in_selected_databases
   1101 	# the goal for this code is to reset status when a tid is an existing task
   1102 	# when parameter is taskid, it doesnt matter if cwd is in tree
   1103 	# find task in selected databases
   1104 	for path in edi_core.selected_path:
   1105 		data_location        = os.path.expanduser(path)
   1106 		data_location_tasks  = '%s/tasks'%data_location
   1107 
   1108 		if not os.path.exists(data_location):
   1109 			sys.exit('%s is unreachable.'%path)
   1110 		tasks = os.listdir(data_location_tasks)
   1111 		if sys.argv[2] in tasks:
   1112 			# found task, setup database below
   1113 			status = ''
   1114 			break
   1115 
   1116 	if status == 'in tree':
   1117 #:get_current_group_in_tree
   1118 		if cwd.split('/')[-1] == 'tree':
   1119 			group = 'root'
   1120 		else:
   1121 			group = cwd.split('/')[-1]
   1122 #:get_position_from_argv2
   1123 		try:
   1124 			position    = int(sys.argv[2])
   1125 		except:
   1126 			sys.exit('%s is invalid position'%sys.argv[2])
   1127 #:find_task_at_position
   1128 		if position < 0:
   1129 			sys.exit('Position %d is invalid.'%position)
   1130 		group_tasks = os.listdir(generate_group_path(group))
   1131 		order_id    = baseconvert(position)
   1132 		tid         = ''
   1133 		for t in group_tasks:
   1134 			# find exact match
   1135 			if order_id == t[:ORDER_ID_LENGTH]:
   1136 				tid = t[ORDER_ID_LENGTH:]
   1137 		if not tid:
   1138 			sys.exit('Position %d does not exist.'%position)
   1139 		sys.argv[2] = tid
   1140 
   1141 	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   1142 #:define tab1_find_task_in_selected_databases_and_setup_data_location
   1143 	if sys.argv[2] == 'root':
   1144 		#set_default_database
   1145 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   1146 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   1147 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1148 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1149 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1150 		if not os.path.exists(edi_core.data_location):
   1151 			sys.exit('%s is unreachable.'%edi_core.data_location)
   1152 	else:
   1153 		for path in edi_core.selected_path:
   1154 			edi_core.data_location        = os.path.expanduser(path)
   1155 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1156 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1157 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1158 
   1159 			if not os.path.exists(edi_core.data_location):
   1160 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   1161 			tasks = os.listdir(edi_core.data_location_tasks)
   1162 			if sys.argv[2] in tasks:
   1163 				break
   1164 #:end
   1165 
   1166 	# Verify that task tid is in database
   1167 	tasks = os.listdir(edi_core.data_location_tasks)
   1168 	if not sys.argv[2] in tasks:
   1169 		sys.exit('%s not found.'%sys.argv[2])
   1170 	# Verify that task is not already a group
   1171 	if is_this_task_a_group(sys.argv[2]):
   1172 		sys.exit('%s is already a group.'%sys.argv[2])
   1173 	print '\n'.join(create_group(sys.argv[2]))
   1174 
   1175 ## print group title for task
   1176 #  @ingroup EDI_CLI
   1177 def show_group_for_task_cli():
   1178 	if len(sys.argv) < 3:
   1179 		sys.exit('Too little parameters.')
   1180 	# Figure out if the command is run in the tree
   1181 #:figure_out_if_in_tree
   1182 	status        = ''
   1183 	cwd           = os.path.realpath(os.getcwd())
   1184 	#loop_on_selected_databases
   1185 	z             = zip(edi_core.selected, edi_core.selected_path)
   1186 	for d,path in z:
   1187 		edi_core.data_location        = os.path.expanduser(path)
   1188 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1189 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1190 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1191 
   1192 		# check path from left
   1193 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   1194 		if real_tree_path == cwd[:len(real_tree_path)]:
   1195 			status = 'in tree'
   1196 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   1197 			break
   1198 
   1199 #:find_task_sysargv2_in_selected_databases
   1200 	# the goal for this code is to reset status when a tid is an existing task
   1201 	# when parameter is taskid, it doesnt matter if cwd is in tree
   1202 	# find task in selected databases
   1203 	for path in edi_core.selected_path:
   1204 		data_location        = os.path.expanduser(path)
   1205 		data_location_tasks  = '%s/tasks'%data_location
   1206 
   1207 		if not os.path.exists(data_location):
   1208 			sys.exit('%s is unreachable.'%path)
   1209 		tasks = os.listdir(data_location_tasks)
   1210 		if sys.argv[2] in tasks:
   1211 			# found task, setup database below
   1212 			status = ''
   1213 			break
   1214 
   1215 	if status == 'in tree':
   1216 #:get_current_group_in_tree
   1217 		if cwd.split('/')[-1] == 'tree':
   1218 			group = 'root'
   1219 		else:
   1220 			group = cwd.split('/')[-1]
   1221 #:get_position_from_argv2
   1222 		try:
   1223 			position    = int(sys.argv[2])
   1224 		except:
   1225 			sys.exit('%s is invalid position'%sys.argv[2])
   1226 #:find_task_at_position
   1227 		if position < 0:
   1228 			sys.exit('Position %d is invalid.'%position)
   1229 		group_tasks = os.listdir(generate_group_path(group))
   1230 		order_id    = baseconvert(position)
   1231 		tid         = ''
   1232 		for t in group_tasks:
   1233 			# find exact match
   1234 			if order_id == t[:ORDER_ID_LENGTH]:
   1235 				tid = t[ORDER_ID_LENGTH:]
   1236 		if not tid:
   1237 			sys.exit('Position %d does not exist.'%position)
   1238 		sys.argv[2] = tid
   1239 
   1240 	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   1241 #:tab1_find_task_in_selected_databases_and_setup_data_location
   1242 	if sys.argv[2] == 'root':
   1243 		#set_default_database
   1244 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   1245 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   1246 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1247 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1248 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1249 		if not os.path.exists(edi_core.data_location):
   1250 			sys.exit('%s is unreachable.'%edi_core.data_location)
   1251 	else:
   1252 		for path in edi_core.selected_path:
   1253 			edi_core.data_location        = os.path.expanduser(path)
   1254 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1255 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1256 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1257 
   1258 			if not os.path.exists(edi_core.data_location):
   1259 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   1260 			tasks = os.listdir(edi_core.data_location_tasks)
   1261 			if sys.argv[2] in tasks:
   1262 				break
   1263 
   1264 	# Verify that task tid is in database
   1265 	tasks = os.listdir(edi_core.data_location_tasks)
   1266 	if not sys.argv[2] in tasks:
   1267 		sys.exit('%s not found.'%sys.argv[2])
   1268 	print '\n'.join(show_group_for_task(sys.argv[2]))
   1269 
   1270 ## delete task or group, or delete task in specified group, keep linked tasks
   1271 #  @ingroup EDI_CLI
   1272 def rm():
   1273 	if len(sys.argv) < 3:
   1274 		sys.exit('Too little parameters.')
   1275 	# Figure out if the command is run in the tree
   1276 #:figure_out_if_in_tree
   1277 	status        = ''
   1278 	cwd           = os.path.realpath(os.getcwd())
   1279 	#loop_on_selected_databases
   1280 	z             = zip(edi_core.selected, edi_core.selected_path)
   1281 	for d,path in z:
   1282 		edi_core.data_location        = os.path.expanduser(path)
   1283 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1284 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1285 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1286 
   1287 		# check path from left
   1288 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   1289 		if real_tree_path == cwd[:len(real_tree_path)]:
   1290 			status = 'in tree'
   1291 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   1292 			break
   1293 
   1294 #:find_task_sysargv2_in_selected_databases
   1295 	# the goal for this code is to reset status when a tid is an existing task
   1296 	# when parameter is taskid, it doesnt matter if cwd is in tree
   1297 	# find task in selected databases
   1298 	for path in edi_core.selected_path:
   1299 		data_location        = os.path.expanduser(path)
   1300 		data_location_tasks  = '%s/tasks'%data_location
   1301 
   1302 		if not os.path.exists(data_location):
   1303 			sys.exit('%s is unreachable.'%path)
   1304 		tasks = os.listdir(data_location_tasks)
   1305 		if sys.argv[2] in tasks:
   1306 			# found task, setup database below
   1307 			status = ''
   1308 			break
   1309 
   1310 	if status == 'in tree':
   1311 #:get_current_group_in_tree
   1312 		if cwd.split('/')[-1] == 'tree':
   1313 			group = 'root'
   1314 		else:
   1315 			group = cwd.split('/')[-1]
   1316 #:get_position_from_argv2
   1317 		try:
   1318 			position    = int(sys.argv[2])
   1319 		except:
   1320 			sys.exit('%s is invalid position'%sys.argv[2])
   1321 #:find_task_at_position
   1322 		if position < 0:
   1323 			sys.exit('Position %d is invalid.'%position)
   1324 		group_tasks = os.listdir(generate_group_path(group))
   1325 		order_id    = baseconvert(position)
   1326 		tid         = ''
   1327 		for t in group_tasks:
   1328 			# find exact match
   1329 			if order_id == t[:ORDER_ID_LENGTH]:
   1330 				tid = t[ORDER_ID_LENGTH:]
   1331 		if not tid:
   1332 			sys.exit('Position %d does not exist.'%position)
   1333 		sys.argv[2] = tid
   1334 
   1335 	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   1336 #:tab1_find_task_in_selected_databases_and_setup_data_location
   1337 	if sys.argv[2] == 'root':
   1338 		#set_default_database
   1339 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   1340 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   1341 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1342 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1343 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1344 		if not os.path.exists(edi_core.data_location):
   1345 			sys.exit('%s is unreachable.'%edi_core.data_location)
   1346 	else:
   1347 		for path in edi_core.selected_path:
   1348 			edi_core.data_location        = os.path.expanduser(path)
   1349 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1350 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1351 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1352 
   1353 			if not os.path.exists(edi_core.data_location):
   1354 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   1355 			tasks = os.listdir(edi_core.data_location_tasks)
   1356 			if sys.argv[2] in tasks:
   1357 				break
   1358 	if len(sys.argv) == 3:
   1359 		if is_this_task_a_group(sys.argv[2]):
   1360 			delete_group(sys.argv[2])
   1361 		else:
   1362 			# Verify that task tid is in database
   1363 			tasks = os.listdir(edi_core.data_location_tasks)
   1364 			if not sys.argv[2] in tasks:
   1365 				sys.exit('%s not found.'%sys.argv[2])
   1366 			delete_task(sys.argv[2])
   1367 	if len(sys.argv) == 4:
   1368 		# Verify that task tid is not root
   1369 		if sys.argv[3] == 'root':
   1370 			sys.exit('root is invalid task')
   1371 		# Verify that task tid is in database
   1372 		tasks = os.listdir(edi_core.data_location_tasks)
   1373 		if not sys.argv[2] in tasks:
   1374 			sys.exit('%s not found.'%sys.argv[2])
   1375 		# Verify group exists
   1376 		if not is_this_task_a_group(sys.argv[2]):
   1377 			sys.exit('%s is not a group.'%sys.argv[2])
   1378 		if not sys.argv[3] in tasks:
   1379 			sys.exit('%s not found.'%sys.argv[3])
   1380 		# delete task in specified group
   1381 		delete_linked_task(sys.argv[2], sys.argv[3])
   1382 
   1383 ## edit description
   1384 #  @ingroup EDI_CLI
   1385 def vi():
   1386 	if len(sys.argv) < 3:
   1387 		sys.exit('Too little parameters.')
   1388 	tid = sys.argv[2]
   1389 
   1390 	# Figure out if the command is run in the tree
   1391 #:figure_out_if_in_tree
   1392 	status        = ''
   1393 	cwd           = os.path.realpath(os.getcwd())
   1394 	#loop_on_selected_databases
   1395 	z             = zip(edi_core.selected, edi_core.selected_path)
   1396 	for d,path in z:
   1397 		edi_core.data_location        = os.path.expanduser(path)
   1398 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1399 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1400 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1401 
   1402 		# check path from left
   1403 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   1404 		if real_tree_path == cwd[:len(real_tree_path)]:
   1405 			status = 'in tree'
   1406 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   1407 			break
   1408 
   1409 #:find_task_sysargv2_in_selected_databases
   1410 	# the goal for this code is to reset status when a tid is an existing task
   1411 	# when parameter is taskid, it doesnt matter if cwd is in tree
   1412 	# find task in selected databases
   1413 	for path in edi_core.selected_path:
   1414 		data_location        = os.path.expanduser(path)
   1415 		data_location_tasks  = '%s/tasks'%data_location
   1416 
   1417 		if not os.path.exists(data_location):
   1418 			sys.exit('%s is unreachable.'%path)
   1419 		tasks = os.listdir(data_location_tasks)
   1420 		if sys.argv[2] in tasks:
   1421 			# found task, setup database below
   1422 			status = ''
   1423 			break
   1424 
   1425 	if status == 'in tree':
   1426 #:get_current_group_in_tree
   1427 		if cwd.split('/')[-1] == 'tree':
   1428 			group = 'root'
   1429 		else:
   1430 			group = cwd.split('/')[-1]
   1431 
   1432 	if (len(sys.argv) == 3) and (not status):
   1433 		# group parameter and not in tree
   1434 		tid = sys.argv[2]
   1435 		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   1436 #:find_task_in_selected_databases_and_setup_data_location
   1437 		if tid == 'root':
   1438 			#set_default_database
   1439 			z = dict(zip(edi_core.selected, edi_core.selected_path))
   1440 			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   1441 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1442 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1443 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1444 			if not os.path.exists(edi_core.data_location):
   1445 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   1446 		elif tid != 'tree':
   1447 			for path in edi_core.selected_path:
   1448 				edi_core.data_location        = os.path.expanduser(path)
   1449 				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1450 				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1451 				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1452 
   1453 				if not os.path.exists(edi_core.data_location):
   1454 					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   1455 				tasks = os.listdir(edi_core.data_location_tasks)
   1456 				if tid in tasks:
   1457 					break
   1458 	if (len(sys.argv) == 3) and (status == 'in tree'):
   1459 		# Find task at given postion
   1460 #:get_position_from_argv2
   1461 		try:
   1462 			position    = int(sys.argv[2])
   1463 		except:
   1464 			sys.exit('%s is invalid position'%sys.argv[2])
   1465 #:find_task_at_position
   1466 		if position < 0:
   1467 			sys.exit('Position %d is invalid.'%position)
   1468 		group_tasks = os.listdir(generate_group_path(group))
   1469 		order_id    = baseconvert(position)
   1470 		tid         = ''
   1471 		for t in group_tasks:
   1472 			# find exact match
   1473 			if order_id == t[:ORDER_ID_LENGTH]:
   1474 				tid = t[ORDER_ID_LENGTH:]
   1475 		if not tid:
   1476 			sys.exit('Position %d does not exist.'%position)
   1477 	if len(sys.argv) == 4:
   1478 		group    = sys.argv[2]
   1479 		try:
   1480 			position = int(sys.argv[3])
   1481 		except:
   1482 			sys.exit('%s is invalid position'%sys.argv[3])
   1483 		# find_task_in_selected_databases_and_setup_data_location needs tid, here tid = group
   1484 		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   1485 #:find_task_in_selected_databases_and_setup_data_location
   1486 		if tid == 'root':
   1487 			#set_default_database
   1488 			z = dict(zip(edi_core.selected, edi_core.selected_path))
   1489 			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   1490 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1491 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1492 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1493 			if not os.path.exists(edi_core.data_location):
   1494 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   1495 		elif tid != 'tree':
   1496 			for path in edi_core.selected_path:
   1497 				edi_core.data_location        = os.path.expanduser(path)
   1498 				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1499 				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1500 				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1501 
   1502 				if not os.path.exists(edi_core.data_location):
   1503 					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   1504 				tasks = os.listdir(edi_core.data_location_tasks)
   1505 				if tid in tasks:
   1506 					break
   1507 		# Verify group exists
   1508 		if not is_this_task_a_group(sys.argv[2]):
   1509 			sys.exit('%s is not a group.'%sys.argv[2])
   1510 #:find_task_at_position
   1511 		if position < 0:
   1512 			sys.exit('Position %d is invalid.'%position)
   1513 		group_tasks = os.listdir(generate_group_path(group))
   1514 		order_id    = baseconvert(position)
   1515 		tid         = ''
   1516 		for t in group_tasks:
   1517 			# find exact match
   1518 			if order_id == t[:ORDER_ID_LENGTH]:
   1519 				tid = t[ORDER_ID_LENGTH:]
   1520 		if not tid:
   1521 			sys.exit('Position %d does not exist.'%position)
   1522 
   1523 	# Verify that task tid is in database
   1524 	tasks = os.listdir(edi_core.data_location_tasks)
   1525 	if not tid in tasks:
   1526 		sys.exit('%s not found.'%tid)
   1527 	edit_task(tid)
   1528 
   1529 ## change order in group. Without group parameter change order in root group, in tree change order in current group
   1530 #  @ingroup EDI_CLI
   1531 def change_order():
   1532 	if len(sys.argv) < 4:
   1533 		sys.exit('Too little parameters.')
   1534 	# Figure out if the command is run in the tree
   1535 #:figure_out_if_in_tree
   1536 	status        = ''
   1537 	cwd           = os.path.realpath(os.getcwd())
   1538 	#loop_on_selected_databases
   1539 	z             = zip(edi_core.selected, edi_core.selected_path)
   1540 	for d,path in z:
   1541 		edi_core.data_location        = os.path.expanduser(path)
   1542 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1543 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1544 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1545 
   1546 		# check path from left
   1547 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   1548 		if real_tree_path == cwd[:len(real_tree_path)]:
   1549 			status = 'in tree'
   1550 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   1551 			break
   1552 
   1553 	if status == 'in tree':
   1554 #:get_current_group_in_tree
   1555 		if cwd.split('/')[-1] == 'tree':
   1556 			group = 'root'
   1557 		else:
   1558 			group = cwd.split('/')[-1]
   1559 	else:
   1560 		group = 'root'
   1561 
   1562 
   1563 	if len(sys.argv) < 5:
   1564 		if not status:
   1565 			sys.exit('Missing group parameter.')
   1566 		at    = sys.argv[2]
   1567 		to    = sys.argv[3]
   1568 	else:
   1569 		group = sys.argv[2]
   1570 		at    = sys.argv[3]
   1571 		to    = sys.argv[4]
   1572 
   1573 		if group == 'root':
   1574 			#set_default_database
   1575 			z = dict(zip(edi_core.selected, edi_core.selected_path))
   1576 			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   1577 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1578 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1579 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1580 			if not os.path.exists(edi_core.data_location):
   1581 				sys.exit('%s is unreachable.'%edi_core.data_location)
   1582 		else:
   1583 			#find_group_in_selected_databases_and_setup_data_location
   1584 			for path in edi_core.selected_path:
   1585 				edi_core.data_location        = os.path.expanduser(path)
   1586 				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1587 				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1588 				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1589 
   1590 				if not os.path.exists(edi_core.data_location):
   1591 					sys.exit('%s is unreachable.'%edi_core.data_location)
   1592 				groups = os.listdir(edi_core.data_location_groups)
   1593 				if group in groups:
   1594 					break
   1595 
   1596 	# Verify group exists
   1597 	if not is_this_task_a_group(group):
   1598 		sys.exit('%s is not a group.'%group)
   1599 	# Verify at and to are numbers
   1600 	try:
   1601 		test = int(at)
   1602 	except:
   1603 		sys.exit('%s is invalid position'%at)
   1604 	try:
   1605 		test = int(to)
   1606 	except:
   1607 		sys.exit('%s is invalid position'%to)
   1608 
   1609 	if int(at) < 0:
   1610 		sys.exit('Position %s is invalid.'%at)
   1611 	if int(to) < 0:
   1612 		sys.exit('Position %s is invalid.'%to)
   1613 	print '\n'.join(change_task_order(group,int(at),int(to)))
   1614 
   1615 ## set status to int parameter
   1616 #  @ingroup EDI_CLI
   1617 def set():
   1618 	if len(sys.argv) < 4:
   1619 		sys.exit('Too little parameters.')
   1620 	# Figure out if the command is run in the tree
   1621 #:figure_out_if_in_tree
   1622 	status        = ''
   1623 	cwd           = os.path.realpath(os.getcwd())
   1624 	#loop_on_selected_databases
   1625 	z             = zip(edi_core.selected, edi_core.selected_path)
   1626 	for d,path in z:
   1627 		edi_core.data_location        = os.path.expanduser(path)
   1628 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1629 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1630 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1631 
   1632 		# check path from left
   1633 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   1634 		if real_tree_path == cwd[:len(real_tree_path)]:
   1635 			status = 'in tree'
   1636 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   1637 			break
   1638 
   1639 #:find_task_sysargv2_in_selected_databases
   1640 	# the goal for this code is to reset status when a tid is an existing task
   1641 	# when parameter is taskid, it doesnt matter if cwd is in tree
   1642 	# find task in selected databases
   1643 	for path in edi_core.selected_path:
   1644 		data_location        = os.path.expanduser(path)
   1645 		data_location_tasks  = '%s/tasks'%data_location
   1646 
   1647 		if not os.path.exists(data_location):
   1648 			sys.exit('%s is unreachable.'%path)
   1649 		tasks = os.listdir(data_location_tasks)
   1650 		if sys.argv[2] in tasks:
   1651 			# found task, setup database below
   1652 			status = ''
   1653 			break
   1654 
   1655 	if status == 'in tree':
   1656 #:get_current_group_in_tree
   1657 		if cwd.split('/')[-1] == 'tree':
   1658 			group = 'root'
   1659 		else:
   1660 			group = cwd.split('/')[-1]
   1661 #:get_position_from_argv2
   1662 		try:
   1663 			position    = int(sys.argv[2])
   1664 		except:
   1665 			sys.exit('%s is invalid position'%sys.argv[2])
   1666 #:find_task_at_position
   1667 		if position < 0:
   1668 			sys.exit('Position %d is invalid.'%position)
   1669 		group_tasks = os.listdir(generate_group_path(group))
   1670 		order_id    = baseconvert(position)
   1671 		tid         = ''
   1672 		for t in group_tasks:
   1673 			# find exact match
   1674 			if order_id == t[:ORDER_ID_LENGTH]:
   1675 				tid = t[ORDER_ID_LENGTH:]
   1676 		if not tid:
   1677 			sys.exit('Position %d does not exist.'%position)
   1678 		sys.argv[2] = tid
   1679 
   1680 	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   1681 #:tab1_find_task_in_selected_databases_and_setup_data_location
   1682 	if sys.argv[2] == 'root':
   1683 		#set_default_database
   1684 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   1685 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   1686 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1687 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1688 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1689 		if not os.path.exists(edi_core.data_location):
   1690 			sys.exit('%s is unreachable.'%edi_core.data_location)
   1691 	else:
   1692 		for path in edi_core.selected_path:
   1693 			edi_core.data_location        = os.path.expanduser(path)
   1694 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1695 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1696 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1697 
   1698 			if not os.path.exists(edi_core.data_location):
   1699 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   1700 			tasks = os.listdir(edi_core.data_location_tasks)
   1701 			if sys.argv[2] in tasks:
   1702 				break
   1703 	# Verify that task tid is in database
   1704 	tasks = os.listdir(edi_core.data_location_tasks)
   1705 	if not sys.argv[2] in tasks:
   1706 		sys.exit('%s not found.'%sys.argv[2])
   1707 	# Verify int_status parameter
   1708 	try:
   1709 		test = int(sys.argv[3])
   1710 	except:
   1711 		sys.exit('int_status %s is invalid.'%sys.argv[3])
   1712 	if test >= len(edi_core.TASK_STATUS):
   1713 		sys.exit('int_status %s is too large.'%sys.argv[3])
   1714 	if test < 0:
   1715 		sys.exit('int_status %s is invalid.'%sys.argv[3])
   1716 	set_status(sys.argv[2],int(sys.argv[3]))
   1717 
   1718 ## set tasks to active. Without parameter set tasks in root group
   1719 #  @ingroup EDI_CLI
   1720 def reset():
   1721 	# Figure out if the command is run in the tree
   1722 #:figure_out_if_in_tree
   1723 	status        = ''
   1724 	cwd           = os.path.realpath(os.getcwd())
   1725 	#loop_on_selected_databases
   1726 	z             = zip(edi_core.selected, edi_core.selected_path)
   1727 	for d,path in z:
   1728 		edi_core.data_location        = os.path.expanduser(path)
   1729 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1730 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1731 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1732 
   1733 		# check path from left
   1734 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   1735 		if real_tree_path == cwd[:len(real_tree_path)]:
   1736 			status = 'in tree'
   1737 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   1738 			break
   1739 
   1740 	if status == 'in tree':
   1741 #:get_current_group_in_tree
   1742 		if cwd.split('/')[-1] == 'tree':
   1743 			group = 'root'
   1744 		else:
   1745 			group = cwd.split('/')[-1]
   1746 
   1747 	if (len(sys.argv) == 2) and (status != 'in tree'):
   1748 #:set_default_database
   1749 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   1750 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   1751 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1752 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1753 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1754 		if not os.path.exists(edi_core.data_location):
   1755 			sys.exit('%s is unreachable.'%edi_core.data_location)
   1756 		group = 'root'
   1757 	if (len(sys.argv) > 2) and (sys.argv[2] == 'root') and (not status):
   1758 		# set default database when group is root and cwd not in tree
   1759 #:set_default_database
   1760 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   1761 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   1762 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1763 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1764 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1765 		if not os.path.exists(edi_core.data_location):
   1766 			sys.exit('%s is unreachable.'%edi_core.data_location)
   1767 		group = 'root'
   1768 	# when group is root and in tree, dont change data_location
   1769 	if (len(sys.argv) > 2) and (sys.argv[2] != 'root'):
   1770 		group = sys.argv[2]
   1771 #:find_group_in_selected_databases_and_setup_data_location
   1772 		for path in edi_core.selected_path:
   1773 			edi_core.data_location        = os.path.expanduser(path)
   1774 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1775 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1776 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1777 
   1778 			if not os.path.exists(edi_core.data_location):
   1779 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   1780 			groups = os.listdir(edi_core.data_location_groups)
   1781 			if group in groups:
   1782 				break
   1783 
   1784 	if not is_this_task_a_group(group):
   1785 		sys.exit('%s is not a group.'%group)
   1786 	reset_group_status(group)
   1787 
   1788 ## search string in tasks folder
   1789 #  @ingroup EDI_CLI
   1790 def search():
   1791 	if len(sys.argv) < 3:
   1792 		sys.exit('Too little parameters.')
   1793 	# Figure out if the command is run in the tree
   1794 #:figure_out_if_in_tree
   1795 	status        = ''
   1796 	cwd           = os.path.realpath(os.getcwd())
   1797 	#loop_on_selected_databases
   1798 	z             = zip(edi_core.selected, edi_core.selected_path)
   1799 	for d,path in z:
   1800 		edi_core.data_location        = os.path.expanduser(path)
   1801 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1802 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1803 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1804 
   1805 		# check path from left
   1806 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   1807 		if real_tree_path == cwd[:len(real_tree_path)]:
   1808 			status = 'in tree'
   1809 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   1810 			break
   1811 
   1812 	if status == 'in tree':
   1813 #:get_current_group_in_tree
   1814 		if cwd.split('/')[-1] == 'tree':
   1815 			group = 'root'
   1816 		else:
   1817 			group = cwd.split('/')[-1]
   1818 		print ''.join(search_string_in_tree(group,sys.argv[2]))
   1819 	else:
   1820 #:loop_on_selected_databases
   1821 		z = zip(edi_core.selected, edi_core.selected_path)
   1822 		for d,path in z:
   1823 			print '%s - %s' % (d,path)
   1824 			edi_core.data_location        = os.path.expanduser(path)
   1825 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1826 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1827 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1828 			if not os.path.exists(edi_core.data_location):
   1829 				sys.exit('%s is unreachable.'%edi_core.data_location)
   1830 			print ''.join(search_string(sys.argv[2]))
   1831 
   1832 ## move task or group
   1833 #  @ingroup EDI_CLI
   1834 def move_task():
   1835 	if len(sys.argv) < 4:
   1836 		sys.exit('Too little parameters.')
   1837 	if len(sys.argv) == 5:
   1838 		tid = sys.argv[2]
   1839 #:find_task_in_selected_databases_and_setup_data_location
   1840 		if tid == 'root':
   1841 			#set_default_database
   1842 			z = dict(zip(edi_core.selected, edi_core.selected_path))
   1843 			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   1844 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1845 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1846 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1847 			if not os.path.exists(edi_core.data_location):
   1848 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   1849 		elif tid != 'tree':
   1850 			for path in edi_core.selected_path:
   1851 				edi_core.data_location        = os.path.expanduser(path)
   1852 				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1853 				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1854 				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1855 
   1856 				if not os.path.exists(edi_core.data_location):
   1857 					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   1858 				tasks = os.listdir(edi_core.data_location_tasks)
   1859 				if tid in tasks:
   1860 					break
   1861 		# Verify parameters
   1862 		# Verify that task tid is not root
   1863 		if sys.argv[3] == 'root':
   1864 			sys.exit('root is invalid task')
   1865 		if not is_this_task_a_group(sys.argv[2]):
   1866 			sys.exit('%s is not a group.'%sys.argv[2])
   1867 		if not is_this_task_a_group(sys.argv[4]):
   1868 			sys.exit('%s is not a group.'%sys.argv[4])
   1869 		# Verify that task tid is in database
   1870 		tasks = os.listdir(edi_core.data_location_tasks)
   1871 		if not sys.argv[3] in tasks:
   1872 			sys.exit('%s not found.'%sys.argv[3])
   1873 		# Verify that when tid is a group, tid is not parent to destination group (sys.argv[3])
   1874 		if is_this_task_a_group(sys.argv[3]):
   1875 			tree_path   = find_group_in_tree(sys.argv[4])
   1876 			parent_path = tree_path.split(sys.argv[4])[0]
   1877 			if sys.argv[3] in parent_path:
   1878 				print tree_path
   1879 				sys.exit('%s is a parent group for %s'%(sys.argv[3],sys.argv[4]))
   1880 		# Verify that group is not move on itself
   1881 		if sys.argv[3] == sys.argv[4]:
   1882 			sys.exit('Moving %s group on itself.'%sys.argv[3])
   1883 		# Verify that source group is not destination group
   1884 		if sys.argv[2] == sys.argv[4]:
   1885 			sys.exit('Source and destination groups are identical %s.'%sys.argv[2])
   1886 		tid = move_task_to_a_group(sys.argv[2],sys.argv[3],sys.argv[4])
   1887 		if len(tid) > edi_core.ID_LENGTH:
   1888 			# Error when the task sys.argv[3] is not found in sys.argv[2]
   1889 			sys.exit(tid)
   1890 		return
   1891 
   1892 	# Always 4 parameters - other parameters are ignored
   1893 	# Parameter 2 is position, find group
   1894 	# Figure out if the command is run in the tree
   1895 #:figure_out_if_in_tree
   1896 	status        = ''
   1897 	cwd           = os.path.realpath(os.getcwd())
   1898 	#loop_on_selected_databases
   1899 	z             = zip(edi_core.selected, edi_core.selected_path)
   1900 	for d,path in z:
   1901 		edi_core.data_location        = os.path.expanduser(path)
   1902 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1903 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1904 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1905 
   1906 		# check path from left
   1907 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   1908 		if real_tree_path == cwd[:len(real_tree_path)]:
   1909 			status = 'in tree'
   1910 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   1911 			break
   1912 
   1913 	if status == 'in tree':
   1914 #:get_current_group_in_tree
   1915 		if cwd.split('/')[-1] == 'tree':
   1916 			group = 'root'
   1917 		else:
   1918 			group = cwd.split('/')[-1]
   1919 #:get_position_from_argv2
   1920 		try:
   1921 			position    = int(sys.argv[2])
   1922 		except:
   1923 			sys.exit('%s is invalid position'%sys.argv[2])
   1924 #:find_task_at_position
   1925 		if position < 0:
   1926 			sys.exit('Position %d is invalid.'%position)
   1927 		group_tasks = os.listdir(generate_group_path(group))
   1928 		order_id    = baseconvert(position)
   1929 		tid         = ''
   1930 		for t in group_tasks:
   1931 			# find exact match
   1932 			if order_id == t[:ORDER_ID_LENGTH]:
   1933 				tid = t[ORDER_ID_LENGTH:]
   1934 		if not tid:
   1935 			sys.exit('Position %d does not exist.'%position)
   1936 		sys.argv[2] = tid
   1937 
   1938 #:tab1_find_task_in_selected_databases_and_setup_data_location
   1939 	if sys.argv[2] == 'root':
   1940 		#set_default_database
   1941 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   1942 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   1943 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1944 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1945 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1946 		if not os.path.exists(edi_core.data_location):
   1947 			sys.exit('%s is unreachable.'%edi_core.data_location)
   1948 	else:
   1949 		for path in edi_core.selected_path:
   1950 			edi_core.data_location        = os.path.expanduser(path)
   1951 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   1952 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   1953 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   1954 
   1955 			if not os.path.exists(edi_core.data_location):
   1956 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   1957 			tasks = os.listdir(edi_core.data_location_tasks)
   1958 			if sys.argv[2] in tasks:
   1959 				break
   1960 
   1961 	# Verify parameters
   1962 	if not 'group' in locals():
   1963 		sys.exit('Invalid parameters.')
   1964 	if not is_this_task_a_group(sys.argv[3]):
   1965 		sys.exit('%s is not a group.'%sys.argv[3])
   1966 	# Verify that when tid is a group, tid is not parent to destination group (sys.argv[3])
   1967 	if is_this_task_a_group(tid):
   1968 		tree_path = find_group_in_tree(sys.argv[3])
   1969 		parent_path = tree_path.split(sys.argv[3])[0]
   1970 		if tid in parent_path:
   1971 			print tree_path
   1972 			sys.exit('%s is a parent group for %s'%(tid,sys.argv[3]))
   1973 	# Verify that group is not move on itself
   1974 	if tid == sys.argv[3]:
   1975 		sys.exit('Moving %s group on itself.'%tid)
   1976 	# Verify that source group is not destination group
   1977 	if group == sys.argv[3]:
   1978 		sys.exit('Source and destination groups are identical %s.'%group)
   1979 	move_task_to_a_group(group,tid,sys.argv[3])
   1980 
   1981 ## copy task to a group. option -E copy description to path, first line in description is filename
   1982 #  @ingroup EDI_CLI
   1983 def copy_task():
   1984 	# Verify parameters
   1985 	if len(sys.argv) < 4:
   1986 		sys.exit('Too little parameters.')
   1987 	# option
   1988 	if sys.argv[2] == '-E':
   1989 		# Verify parameters
   1990 		if len(sys.argv) < 5:
   1991 			sys.exit('Too little parameters.')
   1992 		option      = '-E'
   1993 		sys.argv[2] = sys.argv[3]
   1994 		tid         = sys.argv[3]
   1995 	else:
   1996 		option      = ''
   1997 		tid         = sys.argv[2]
   1998 
   1999 	# Figure out if the command is run in the tree
   2000 #:figure_out_if_in_tree
   2001 	status        = ''
   2002 	cwd           = os.path.realpath(os.getcwd())
   2003 	#loop_on_selected_databases
   2004 	z             = zip(edi_core.selected, edi_core.selected_path)
   2005 	for d,path in z:
   2006 		edi_core.data_location        = os.path.expanduser(path)
   2007 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2008 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2009 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2010 
   2011 		# check path from left
   2012 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   2013 		if real_tree_path == cwd[:len(real_tree_path)]:
   2014 			status = 'in tree'
   2015 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   2016 			break
   2017 
   2018 #:find_task_sysargv2_in_selected_databases
   2019 	# the goal for this code is to reset status when a tid is an existing task
   2020 	# when parameter is taskid, it doesnt matter if cwd is in tree
   2021 	# find task in selected databases
   2022 	for path in edi_core.selected_path:
   2023 		data_location        = os.path.expanduser(path)
   2024 		data_location_tasks  = '%s/tasks'%data_location
   2025 
   2026 		if not os.path.exists(data_location):
   2027 			sys.exit('%s is unreachable.'%path)
   2028 		tasks = os.listdir(data_location_tasks)
   2029 		if sys.argv[2] in tasks:
   2030 			# found task, setup database below
   2031 			status = ''
   2032 			break
   2033 
   2034 	if status == 'in tree':
   2035 #:get_current_group_in_tree
   2036 		if cwd.split('/')[-1] == 'tree':
   2037 			group = 'root'
   2038 		else:
   2039 			group = cwd.split('/')[-1]
   2040 #:get_position_from_argv2
   2041 		try:
   2042 			position    = int(sys.argv[2])
   2043 		except:
   2044 			sys.exit('%s is invalid position'%sys.argv[2])
   2045 #:find_task_at_position
   2046 		if position < 0:
   2047 			sys.exit('Position %d is invalid.'%position)
   2048 		group_tasks = os.listdir(generate_group_path(group))
   2049 		order_id    = baseconvert(position)
   2050 		tid         = ''
   2051 		for t in group_tasks:
   2052 			# find exact match
   2053 			if order_id == t[:ORDER_ID_LENGTH]:
   2054 				tid = t[ORDER_ID_LENGTH:]
   2055 		if not tid:
   2056 			sys.exit('Position %d does not exist.'%position)
   2057 
   2058 	if option == '-E':
   2059 		# Export task to a file
   2060 		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   2061 #:find_task_in_selected_databases_and_setup_data_location
   2062 		if tid == 'root':
   2063 			#set_default_database
   2064 			z = dict(zip(edi_core.selected, edi_core.selected_path))
   2065 			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   2066 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2067 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2068 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2069 			if not os.path.exists(edi_core.data_location):
   2070 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   2071 		elif tid != 'tree':
   2072 			for path in edi_core.selected_path:
   2073 				edi_core.data_location        = os.path.expanduser(path)
   2074 				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2075 				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2076 				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2077 
   2078 				if not os.path.exists(edi_core.data_location):
   2079 					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   2080 				tasks = os.listdir(edi_core.data_location_tasks)
   2081 				if tid in tasks:
   2082 					break
   2083 		if not os.path.exists(sys.argv[4]):
   2084 			sys.exit('%s is unreachable.'%sys.argv[4])
   2085 
   2086 		# Verify that task tid is in database
   2087 		tasks = os.listdir(edi_core.data_location_tasks)
   2088 		if not tid in tasks:
   2089 			sys.exit('%s not found.'%tid)
   2090 
   2091 		r = export_task_to_a_file(tid,sys.argv[4])
   2092 		print 'Exported task to %s'%r
   2093 	else:
   2094 		# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   2095 #:find_task_in_selected_databases_and_setup_data_location
   2096 		if tid == 'root':
   2097 			#set_default_database
   2098 			z = dict(zip(edi_core.selected, edi_core.selected_path))
   2099 			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   2100 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2101 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2102 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2103 			if not os.path.exists(edi_core.data_location):
   2104 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   2105 		elif tid != 'tree':
   2106 			for path in edi_core.selected_path:
   2107 				edi_core.data_location        = os.path.expanduser(path)
   2108 				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2109 				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2110 				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2111 
   2112 				if not os.path.exists(edi_core.data_location):
   2113 					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   2114 				tasks = os.listdir(edi_core.data_location_tasks)
   2115 				if tid in tasks:
   2116 					break
   2117 		# Verify that task tid is not root
   2118 		if tid == 'root':
   2119 			sys.exit('root is invalid task')
   2120 		# Verify that task tid is in database
   2121 		tasks = os.listdir(edi_core.data_location_tasks)
   2122 		if not tid in tasks:
   2123 			sys.exit('%s not found.'%tid)
   2124 
   2125 		if not is_this_task_a_group(sys.argv[3]):
   2126 			sys.exit('%s is not a group.'%sys.argv[3])
   2127 		if tid == sys.argv[3]:
   2128 			sys.exit('Source and destination are identical.')
   2129 		# Verify that when tid is a group, tid is not parent to destination group (sys.argv[3])
   2130 		if is_this_task_a_group(tid):
   2131 			tree_path = find_group_in_tree(sys.argv[3])
   2132 			parent_path = tree_path.split(sys.argv[3])[0]
   2133 			if tid in parent_path:
   2134 				print tree_path
   2135 				sys.exit('%s is a parent group for %s'%(tid,sys.argv[3]))
   2136 		print copy_task_to_a_group(tid,sys.argv[3])
   2137 
   2138 ## add a reference in group
   2139 #  @ingroup EDI_CLI
   2140 def link_task():
   2141 	if len(sys.argv) < 4:
   2142 		sys.exit('Too little parameters.')
   2143 	# Figure out if the command is run in the tree
   2144 #:figure_out_if_in_tree
   2145 	status        = ''
   2146 	cwd           = os.path.realpath(os.getcwd())
   2147 	#loop_on_selected_databases
   2148 	z             = zip(edi_core.selected, edi_core.selected_path)
   2149 	for d,path in z:
   2150 		edi_core.data_location        = os.path.expanduser(path)
   2151 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2152 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2153 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2154 
   2155 		# check path from left
   2156 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   2157 		if real_tree_path == cwd[:len(real_tree_path)]:
   2158 			status = 'in tree'
   2159 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   2160 			break
   2161 
   2162 #:find_task_sysargv2_in_selected_databases
   2163 	# the goal for this code is to reset status when a tid is an existing task
   2164 	# when parameter is taskid, it doesnt matter if cwd is in tree
   2165 	# find task in selected databases
   2166 	for path in edi_core.selected_path:
   2167 		data_location        = os.path.expanduser(path)
   2168 		data_location_tasks  = '%s/tasks'%data_location
   2169 
   2170 		if not os.path.exists(data_location):
   2171 			sys.exit('%s is unreachable.'%path)
   2172 		tasks = os.listdir(data_location_tasks)
   2173 		if sys.argv[2] in tasks:
   2174 			# found task, setup database below
   2175 			status = ''
   2176 			break
   2177 
   2178 	if status == 'in tree':
   2179 #:get_current_group_in_tree
   2180 		if cwd.split('/')[-1] == 'tree':
   2181 			group = 'root'
   2182 		else:
   2183 			group = cwd.split('/')[-1]
   2184 #:get_position_from_argv2
   2185 		try:
   2186 			position    = int(sys.argv[2])
   2187 		except:
   2188 			sys.exit('%s is invalid position'%sys.argv[2])
   2189 #:find_task_at_position
   2190 		if position < 0:
   2191 			sys.exit('Position %d is invalid.'%position)
   2192 		group_tasks = os.listdir(generate_group_path(group))
   2193 		order_id    = baseconvert(position)
   2194 		tid         = ''
   2195 		for t in group_tasks:
   2196 			# find exact match
   2197 			if order_id == t[:ORDER_ID_LENGTH]:
   2198 				tid = t[ORDER_ID_LENGTH:]
   2199 		if not tid:
   2200 			sys.exit('Position %d does not exist.'%position)
   2201 		sys.argv[2] = tid
   2202 
   2203 	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   2204 #:tab1_find_task_in_selected_databases_and_setup_data_location
   2205 	if sys.argv[2] == 'root':
   2206 		#set_default_database
   2207 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   2208 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   2209 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2210 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2211 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2212 		if not os.path.exists(edi_core.data_location):
   2213 			sys.exit('%s is unreachable.'%edi_core.data_location)
   2214 	else:
   2215 		for path in edi_core.selected_path:
   2216 			edi_core.data_location        = os.path.expanduser(path)
   2217 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2218 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2219 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2220 
   2221 			if not os.path.exists(edi_core.data_location):
   2222 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   2223 			tasks = os.listdir(edi_core.data_location_tasks)
   2224 			if sys.argv[2] in tasks:
   2225 				break
   2226 	# Verify that task tid is in database
   2227 	tasks = os.listdir(edi_core.data_location_tasks)
   2228 	if not sys.argv[2] in tasks:
   2229 		sys.exit('%s not found.'%sys.argv[2])
   2230 	# Verify parameters
   2231 	if not is_this_task_a_group(sys.argv[3]):
   2232 		sys.exit('%s is not a group.'%sys.argv[3])
   2233 	if sys.argv[3] == find_group_containing_task(sys.argv[2]):
   2234 		sys.exit('Task %s is already in group %s.'%(sys.argv[2],sys.argv[3]))
   2235 	add_task_reference_to_a_group(sys.argv[2],sys.argv[3])
   2236 
   2237 ## print task filesystem path
   2238 #  @ingroup EDI_CLI
   2239 def get_task_path():
   2240 	if len(sys.argv) < 3:
   2241 		sys.exit('Too little parameters.')
   2242 	# Figure out if the command is run in the tree
   2243 #:figure_out_if_in_tree
   2244 	status        = ''
   2245 	cwd           = os.path.realpath(os.getcwd())
   2246 	#loop_on_selected_databases
   2247 	z             = zip(edi_core.selected, edi_core.selected_path)
   2248 	for d,path in z:
   2249 		edi_core.data_location        = os.path.expanduser(path)
   2250 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2251 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2252 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2253 
   2254 		# check path from left
   2255 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   2256 		if real_tree_path == cwd[:len(real_tree_path)]:
   2257 			status = 'in tree'
   2258 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   2259 			break
   2260 
   2261 #:find_task_sysargv2_in_selected_databases
   2262 	# the goal for this code is to reset status when a tid is an existing task
   2263 	# when parameter is taskid, it doesnt matter if cwd is in tree
   2264 	# find task in selected databases
   2265 	for path in edi_core.selected_path:
   2266 		data_location        = os.path.expanduser(path)
   2267 		data_location_tasks  = '%s/tasks'%data_location
   2268 
   2269 		if not os.path.exists(data_location):
   2270 			sys.exit('%s is unreachable.'%path)
   2271 		tasks = os.listdir(data_location_tasks)
   2272 		if sys.argv[2] in tasks:
   2273 			# found task, setup database below
   2274 			status = ''
   2275 			break
   2276 
   2277 	if status == 'in tree':
   2278 #:get_current_group_in_tree
   2279 		if cwd.split('/')[-1] == 'tree':
   2280 			group = 'root'
   2281 		else:
   2282 			group = cwd.split('/')[-1]
   2283 #:get_position_from_argv2
   2284 		try:
   2285 			position    = int(sys.argv[2])
   2286 		except:
   2287 			sys.exit('%s is invalid position'%sys.argv[2])
   2288 #:find_task_at_position
   2289 		if position < 0:
   2290 			sys.exit('Position %d is invalid.'%position)
   2291 		group_tasks = os.listdir(generate_group_path(group))
   2292 		order_id    = baseconvert(position)
   2293 		tid         = ''
   2294 		for t in group_tasks:
   2295 			# find exact match
   2296 			if order_id == t[:ORDER_ID_LENGTH]:
   2297 				tid = t[ORDER_ID_LENGTH:]
   2298 		if not tid:
   2299 			sys.exit('Position %d does not exist.'%position)
   2300 		sys.argv[2] = tid
   2301 
   2302 	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   2303 #:tab1_find_task_in_selected_databases_and_setup_data_location
   2304 	if sys.argv[2] == 'root':
   2305 		#set_default_database
   2306 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   2307 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   2308 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2309 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2310 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2311 		if not os.path.exists(edi_core.data_location):
   2312 			sys.exit('%s is unreachable.'%edi_core.data_location)
   2313 	else:
   2314 		for path in edi_core.selected_path:
   2315 			edi_core.data_location        = os.path.expanduser(path)
   2316 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2317 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2318 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2319 
   2320 			if not os.path.exists(edi_core.data_location):
   2321 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   2322 			tasks = os.listdir(edi_core.data_location_tasks)
   2323 			if sys.argv[2] in tasks:
   2324 				break
   2325 	# Verify that task tid is in database
   2326 	tasks = os.listdir(edi_core.data_location_tasks)
   2327 	if not sys.argv[2] in tasks:
   2328 		sys.exit('%s not found.'%sys.argv[2])
   2329 	print generate_task_path(sys.argv[2])
   2330 
   2331 ## print tree path
   2332 #  @ingroup EDI_CLI
   2333 def tree():
   2334 	print edi_core.data_location_tree
   2335 
   2336 	DATABASE_NAME = 0
   2337 	DATABASE_PATH = 1
   2338 	print
   2339 	print 'trees'
   2340 	for d in edi_core.databases:
   2341 		print '%s - %s/tree' % (d[DATABASE_NAME], d[DATABASE_PATH])
   2342 
   2343 ## enable/disable (set) status filter
   2344 #  @ingroup EDI_CLI
   2345 def set_status_filter():
   2346 	if len(sys.argv)<3:
   2347 		print edi_core.status_filters_d
   2348 	else:
   2349 		if len(sys.argv)<4:
   2350 			sys.exit('Too little parameters.')
   2351 		status_name = sys.argv[2]
   2352 		state       = sys.argv[3]
   2353 
   2354 		# verify parameters
   2355 		task_status = [i.strip().lower() for i in edi_core.TASK_STATUS]
   2356 		if not status_name.lower() in task_status:
   2357 			sys.exit('%s is invalid status_filter. Possible status filter are %s.'%(status_name,','.join(task_status)))
   2358 		if not state in edi_core.STATUS_FILTER_STATES:
   2359 			sys.exit('%s is invalid state. Possible states are %s.'%(state,','.join(edi_core.STATUS_FILTER_STATES)))
   2360 
   2361 #:define load_ini_file
   2362 		f      = open(os.path.expanduser('~/.easydoneit.ini'))
   2363 		# load config from user home
   2364 		config = ConfigParser.ConfigParser()
   2365 		config.readfp(f)
   2366 		f.close()
   2367 #:end
   2368 		config.set('filters',status_name,state)
   2369 
   2370 #:define save_ini_file
   2371 		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
   2372 		config.write(f)
   2373 		f.close()
   2374 #:end
   2375 
   2376 ## set path for database
   2377 #  @ingroup EDI_CLI
   2378 def data():
   2379 	if len(sys.argv)<3:
   2380 		print 'Selected data_location'
   2381 		print edi_core.data_location
   2382 		DATABASE_NAME = 0
   2383 		DATABASE_PATH = 1
   2384 		print
   2385 		print 'Available databases'
   2386 		for d in edi_core.databases:
   2387 			print '%s - %s' % (d[DATABASE_NAME], d[DATABASE_PATH])
   2388 	else:
   2389 		if len(sys.argv)<4:
   2390 			sys.exit('Too little parameters.')
   2391 #:load_ini_file
   2392 		f      = open(os.path.expanduser('~/.easydoneit.ini'))
   2393 		# load config from user home
   2394 		config = ConfigParser.ConfigParser()
   2395 		config.readfp(f)
   2396 		f.close()
   2397 		if sys.argv[2] == '-d':
   2398 			name           = sys.argv[3]
   2399 			try:
   2400 				path           = config.get('data',name)
   2401 			except:
   2402 				sys.exit('%s is invalid database name.'%name)
   2403 			if name == 'location':
   2404 				sys.exit('%s is invalid database name.'%name)
   2405 
   2406 			# remove database from selected configuration and check that at least one database is selected
   2407 			selected       = config.get('locations','selected')
   2408 			selected_l     = selected.split(',')
   2409 			new_selected_l = []
   2410 			for i in selected_l:
   2411 				if not name in i:
   2412 					new_selected_l.append(i)
   2413 			if not new_selected_l:
   2414 				sys.exit('Select more databases before deleting %s'%name)
   2415 			new_selected   = ','.join(new_selected_l)
   2416 			config.set('locations','selected',new_selected)
   2417 
   2418 			# delete database folder from file system
   2419 			# delete database from config file
   2420 
   2421 			# delete database folder from file system
   2422 			if os.path.exists(path):
   2423 				shutil.rmtree(path)
   2424 			# delete database from config file - data, selected and default_add_in
   2425 			config.remove_option('data',name)
   2426 
   2427 			default        = config.get('locations','default_add_in')
   2428 			if name == default:
   2429 				default = new_selected_l[0]
   2430 			config.set('locations','default_add_in',default)
   2431 
   2432 			#save_ini_file
   2433 			f              = open(os.path.expanduser('~/.easydoneit.ini'),'w')
   2434 			config.write(f)
   2435 			f.close()
   2436 			#end
   2437 
   2438 			print 'Deleted database %s - %s' % (name,path)
   2439 			print '\nSelected databases'
   2440 			print new_selected
   2441 			print '\nDefault for new tasks'
   2442 			print default
   2443 			return
   2444 
   2445 		name = sys.argv[2]
   2446 		if name == 'location':
   2447 			sys.exit('%s is invalid database name.'%name)
   2448 		path = os.path.expanduser(sys.argv[3])
   2449 
   2450 		config.set('data',name,path)
   2451 #:save_ini_file
   2452 		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
   2453 		config.write(f)
   2454 		f.close()
   2455 		edi_core.data_location = path
   2456 		init()
   2457 
   2458 ## generate html for tasks
   2459 #  @ingroup EDI_CLI
   2460 def html_cli():
   2461 	# generate html header and content
   2462 	edi_core.list_option = 'html'
   2463 
   2464 	html_header = '''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
   2465 <html>
   2466   <head>
   2467     <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
   2468     <title>Tasks</title>
   2469     <style type="text/css">
   2470       .subject {text-align: left}
   2471       .plannedStartDateTime {text-align: right}
   2472       .priority {text-align: right}
   2473       .inactive {color: #5E5E5E}
   2474       .late {color: #A020F0}
   2475       .active {color: #000000}
   2476       .duesoon {color: #FF8000}
   2477       .overdue {color: #FF0000}
   2478       .completed {color: #037700}
   2479 
   2480       body {
   2481           color: #333;
   2482           background-color: white;
   2483           font: 11px verdana, arial, helvetica, sans-serif;
   2484       }
   2485 
   2486       /* Styles for the title and table caption */
   2487       h1, caption {
   2488           text-align: center;
   2489           font-size: 18px;
   2490           font-weight: 900;
   2491           color: #778;
   2492       }
   2493 
   2494       /* Styles for the whole table */
   2495       #table {
   2496           border-collapse: collapse;
   2497           border: 2px solid #ebedff;
   2498           margin: 10px;
   2499           padding: 0;
   2500       }
   2501 
   2502       /* Styles for the header row */
   2503       .header {
   2504           font: bold 12px/14px verdana, arial, helvetica, sans-serif;
   2505           color: #07a;
   2506           background-color: #ebedff;
   2507       }
   2508 
   2509       /* Mark the column that is sorted on */
   2510       #sorted {
   2511           text-decoration: underline;
   2512       }
   2513 
   2514       /* Styles for a specific column */
   2515       .subject {
   2516           font-weight: bold;
   2517       }
   2518 
   2519       /* Styles for regular table cells */
   2520       td {
   2521           padding: 5px;
   2522           border: 2px solid #ebedff;
   2523       }
   2524 
   2525       /* Styles for table header cells */
   2526       th {
   2527           padding: 5px;
   2528           border: 2px solid #ebedff;
   2529       }
   2530 
   2531     </style>
   2532   </head>
   2533   <body>
   2534   <h1>Tasks</h1>
   2535     <table border="1" id="table">
   2536       <thead>
   2537         <tr class="header">
   2538           <th class="subject" scope="col">Subject</th>
   2539           <th class="description" scope="col">Description</th>
   2540         </tr>
   2541       </thead>
   2542       <tbody>'''
   2543 
   2544 	html_footer = '''      </tbody>
   2545     </table>
   2546   </body>
   2547 </html>'''
   2548 
   2549       	print html_header
   2550 	ls_generic()
   2551 	print html_footer
   2552 
   2553 ## list selected databases or set selected databases
   2554 #  @ingroup EDI_CLI
   2555 def selected_cli():
   2556 	if len(sys.argv)>3:
   2557 		sys.exit('Too many parameters.')
   2558 	if len(sys.argv)<3:
   2559 		print 'Selected databases'
   2560 		print ','.join(edi_core.selected)
   2561 		print
   2562 		z = zip(edi_core.selected, edi_core.selected_path)
   2563 		for d,p in z:
   2564 			print '%s - %s' % (d,p)
   2565 	if len(sys.argv)==3:
   2566 #:load_ini_file
   2567 		f      = open(os.path.expanduser('~/.easydoneit.ini'))
   2568 		# load config from user home
   2569 		config = ConfigParser.ConfigParser()
   2570 		config.readfp(f)
   2571 		f.close()
   2572 		# Verify parameter
   2573 		selected = sys.argv[2].split(',')
   2574 		if 'location' in selected:
   2575 			sys.exit('location is invalid database name.')
   2576 		for d in selected:
   2577 			if not d in dict(edi_core.databases).keys():
   2578 				sys.exit('%s is invalid database name.'%d)
   2579 		if not edi_core.default_add_in in selected:
   2580 			# default becomes first selected database
   2581 			print 'Default database %s is not selected'%edi_core.default_add_in
   2582 			print '%s is now default'%sys.argv[2].split(',')[0]
   2583 			config.set('locations','default_add_in',sys.argv[2].split(',')[0])
   2584 		config.set('locations','selected',sys.argv[2])
   2585 #:save_ini_file
   2586 		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
   2587 		config.write(f)
   2588 		f.close()
   2589 
   2590 ## set default database
   2591 #  @ingroup EDI_CLI
   2592 def default_cli():
   2593 	if len(sys.argv)>3:
   2594 		sys.exit('Too many parameters.')
   2595 	if len(sys.argv)<3:
   2596 		print 'Default for new tasks'
   2597 		print edi_core.default_add_in
   2598 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   2599 		print z[edi_core.default_add_in]
   2600 	if len(sys.argv)==3:
   2601 		# Verify parameter
   2602 		if not sys.argv[2] in edi_core.selected:
   2603 			sys.exit('%s is not selected'%sys.argv[2])
   2604 #:load_ini_file
   2605 		f      = open(os.path.expanduser('~/.easydoneit.ini'))
   2606 		# load config from user home
   2607 		config = ConfigParser.ConfigParser()
   2608 		config.readfp(f)
   2609 		f.close()
   2610 		config.set('locations','default_add_in',sys.argv[2])
   2611 #:save_ini_file
   2612 		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
   2613 		config.write(f)
   2614 		f.close()
   2615 
   2616 
   2617 ## copy task or group to database/group
   2618 #  @ingroup EDI_CLI
   2619 def cpb_cli():
   2620 	if len(sys.argv) < 5:
   2621 		sys.exit('Too little parameters.')
   2622 	# Figure out if the command is run in the tree
   2623 #:figure_out_if_in_tree
   2624 	status        = ''
   2625 	cwd           = os.path.realpath(os.getcwd())
   2626 	#loop_on_selected_databases
   2627 	z             = zip(edi_core.selected, edi_core.selected_path)
   2628 	for d,path in z:
   2629 		edi_core.data_location        = os.path.expanduser(path)
   2630 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2631 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2632 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2633 
   2634 		# check path from left
   2635 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   2636 		if real_tree_path == cwd[:len(real_tree_path)]:
   2637 			status = 'in tree'
   2638 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   2639 			break
   2640 
   2641 #:find_task_sysargv2_in_selected_databases
   2642 	# the goal for this code is to reset status when a tid is an existing task
   2643 	# when parameter is taskid, it doesnt matter if cwd is in tree
   2644 	# find task in selected databases
   2645 	for path in edi_core.selected_path:
   2646 		data_location        = os.path.expanduser(path)
   2647 		data_location_tasks  = '%s/tasks'%data_location
   2648 
   2649 		if not os.path.exists(data_location):
   2650 			sys.exit('%s is unreachable.'%path)
   2651 		tasks = os.listdir(data_location_tasks)
   2652 		if sys.argv[2] in tasks:
   2653 			# found task, setup database below
   2654 			status = ''
   2655 			break
   2656 
   2657 	if status == 'in tree':
   2658 #:get_current_group_in_tree
   2659 		if cwd.split('/')[-1] == 'tree':
   2660 			group = 'root'
   2661 		else:
   2662 			group = cwd.split('/')[-1]
   2663 #:get_position_from_argv2
   2664 		try:
   2665 			position    = int(sys.argv[2])
   2666 		except:
   2667 			sys.exit('%s is invalid position'%sys.argv[2])
   2668 #:find_task_at_position
   2669 		if position < 0:
   2670 			sys.exit('Position %d is invalid.'%position)
   2671 		group_tasks = os.listdir(generate_group_path(group))
   2672 		order_id    = baseconvert(position)
   2673 		tid         = ''
   2674 		for t in group_tasks:
   2675 			# find exact match
   2676 			if order_id == t[:ORDER_ID_LENGTH]:
   2677 				tid = t[ORDER_ID_LENGTH:]
   2678 		if not tid:
   2679 			sys.exit('Position %d does not exist.'%position)
   2680 		sys.argv[2] = tid
   2681 
   2682 	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   2683 #:tab1_find_task_in_selected_databases_and_setup_data_location
   2684 	if sys.argv[2] == 'root':
   2685 		#set_default_database
   2686 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   2687 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   2688 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2689 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2690 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2691 		if not os.path.exists(edi_core.data_location):
   2692 			sys.exit('%s is unreachable.'%edi_core.data_location)
   2693 	else:
   2694 		for path in edi_core.selected_path:
   2695 			edi_core.data_location        = os.path.expanduser(path)
   2696 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2697 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2698 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2699 
   2700 			if not os.path.exists(edi_core.data_location):
   2701 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   2702 			tasks = os.listdir(edi_core.data_location_tasks)
   2703 			if sys.argv[2] in tasks:
   2704 				break
   2705 	# Verify parameters
   2706 	if not sys.argv[3] in edi_core.selected:
   2707 		sys.exit('%s database is not selected.'%sys.argv[3])
   2708 	# Verify that task tid is not root
   2709 	if sys.argv[2] == 'root':
   2710 		sys.exit('root is invalid task')
   2711 	# Verify that task tid is in database
   2712 	tasks = os.listdir(edi_core.data_location_tasks)
   2713 	if not sys.argv[2] in tasks:
   2714 		sys.exit('%s not found.'%sys.argv[2])
   2715 	z                    = dict(zip(edi_core.selected, edi_core.selected_path))
   2716 	data_location        = os.path.expanduser(z[sys.argv[3]])
   2717 	data_location_groups = '%s/groups'%data_location
   2718 	if not os.path.exists('%s/%s'%(data_location_groups,sys.argv[4])):
   2719 		sys.exit('Missing destination group %s'%sys.argv[4])
   2720 	print copy_task_to_database(sys.argv[2],sys.argv[3],sys.argv[4])
   2721 
   2722 ## move task or group to database
   2723 #  @ingroup EDI_CLI
   2724 # 2 group<br>
   2725 # 3 task|group<br>
   2726 # 4 location<br>
   2727 # 5 group
   2728 def mvb_cli():
   2729 	if len(sys.argv) < 5:
   2730 		sys.exit('Too little parameters.')
   2731 	# Figure out if the command is run in the tree
   2732 #:figure_out_if_in_tree
   2733 	status        = ''
   2734 	cwd           = os.path.realpath(os.getcwd())
   2735 	#loop_on_selected_databases
   2736 	z             = zip(edi_core.selected, edi_core.selected_path)
   2737 	for d,path in z:
   2738 		edi_core.data_location        = os.path.expanduser(path)
   2739 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2740 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2741 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2742 
   2743 		# check path from left
   2744 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   2745 		if real_tree_path == cwd[:len(real_tree_path)]:
   2746 			status = 'in tree'
   2747 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   2748 			break
   2749 
   2750 #:find_task_sysargv2_in_selected_databases
   2751 	# the goal for this code is to reset status when a tid is an existing task
   2752 	# when parameter is taskid, it doesnt matter if cwd is in tree
   2753 	# find task in selected databases
   2754 	for path in edi_core.selected_path:
   2755 		data_location        = os.path.expanduser(path)
   2756 		data_location_tasks  = '%s/tasks'%data_location
   2757 
   2758 		if not os.path.exists(data_location):
   2759 			sys.exit('%s is unreachable.'%path)
   2760 		tasks = os.listdir(data_location_tasks)
   2761 		if sys.argv[2] in tasks:
   2762 			# found task, setup database below
   2763 			status = ''
   2764 			break
   2765 
   2766 	if status == 'in tree':
   2767 #:get_current_group_in_tree
   2768 		if cwd.split('/')[-1] == 'tree':
   2769 			group = 'root'
   2770 		else:
   2771 			group = cwd.split('/')[-1]
   2772 #:get_position_from_argv2
   2773 		try:
   2774 			position    = int(sys.argv[2])
   2775 		except:
   2776 			sys.exit('%s is invalid position'%sys.argv[2])
   2777 #:find_task_at_position
   2778 		if position < 0:
   2779 			sys.exit('Position %d is invalid.'%position)
   2780 		group_tasks = os.listdir(generate_group_path(group))
   2781 		order_id    = baseconvert(position)
   2782 		tid         = ''
   2783 		for t in group_tasks:
   2784 			# find exact match
   2785 			if order_id == t[:ORDER_ID_LENGTH]:
   2786 				tid = t[ORDER_ID_LENGTH:]
   2787 		if not tid:
   2788 			sys.exit('Position %d does not exist.'%position)
   2789 		sys.argv[2]       = tid
   2790 		database          = sys.argv[3]
   2791 		destination_group = sys.argv[4]
   2792 	else:
   2793 		if len(sys.argv) < 6:
   2794 			sys.exit('Too little parameters.')
   2795 		group             = sys.argv[2]
   2796 		tid               = sys.argv[3]
   2797 		database          = sys.argv[4]
   2798 		destination_group = sys.argv[5]
   2799 
   2800 	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   2801 #:tab1_find_task_in_selected_databases_and_setup_data_location
   2802 	if sys.argv[2] == 'root':
   2803 		#set_default_database
   2804 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   2805 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   2806 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2807 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2808 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2809 		if not os.path.exists(edi_core.data_location):
   2810 			sys.exit('%s is unreachable.'%edi_core.data_location)
   2811 	else:
   2812 		for path in edi_core.selected_path:
   2813 			edi_core.data_location        = os.path.expanduser(path)
   2814 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2815 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2816 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2817 
   2818 			if not os.path.exists(edi_core.data_location):
   2819 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   2820 			tasks = os.listdir(edi_core.data_location_tasks)
   2821 			if sys.argv[2] in tasks:
   2822 				break
   2823 	# Verify parameters
   2824 	if not database in edi_core.selected:
   2825 		sys.exit('%s database is not selected.'%database)
   2826 	# Verify that task tid is not root
   2827 	if tid == 'root':
   2828 		sys.exit('root is invalid task')
   2829 	if not is_this_task_a_group(group):
   2830 		sys.exit('%s is not a group.'%group)
   2831 	# Verify that task tid is in database
   2832 	tasks = os.listdir(edi_core.data_location_tasks)
   2833 	if not tid in tasks:
   2834 		sys.exit('%s not found.'%tid)
   2835 	z                    = dict(zip(edi_core.selected, edi_core.selected_path))
   2836 	data_location        = os.path.expanduser(z[database])
   2837 	data_location_groups = '%s/groups'%data_location
   2838 	if not os.path.exists('%s/%s'%(data_location_groups,destination_group)):
   2839 		sys.exit('Missing destination group %s'%destination_group)
   2840 	print move_task_to_a_group_to_database(group,tid,database,destination_group)
   2841 
   2842 ## set or show foreground color
   2843 #  @ingroup EDI_CLI
   2844 def fc_cli():
   2845 	if len(sys.argv) < 3:
   2846 		sys.exit('Too little parameters.')
   2847 	# Figure out if the command is run in the tree
   2848 #:figure_out_if_in_tree
   2849 	status        = ''
   2850 	cwd           = os.path.realpath(os.getcwd())
   2851 	#loop_on_selected_databases
   2852 	z             = zip(edi_core.selected, edi_core.selected_path)
   2853 	for d,path in z:
   2854 		edi_core.data_location        = os.path.expanduser(path)
   2855 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2856 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2857 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2858 
   2859 		# check path from left
   2860 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   2861 		if real_tree_path == cwd[:len(real_tree_path)]:
   2862 			status = 'in tree'
   2863 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   2864 			break
   2865 
   2866 #:find_task_sysargv2_in_selected_databases
   2867 	# the goal for this code is to reset status when a tid is an existing task
   2868 	# when parameter is taskid, it doesnt matter if cwd is in tree
   2869 	# find task in selected databases
   2870 	for path in edi_core.selected_path:
   2871 		data_location        = os.path.expanduser(path)
   2872 		data_location_tasks  = '%s/tasks'%data_location
   2873 
   2874 		if not os.path.exists(data_location):
   2875 			sys.exit('%s is unreachable.'%path)
   2876 		tasks = os.listdir(data_location_tasks)
   2877 		if sys.argv[2] in tasks:
   2878 			# found task, setup database below
   2879 			status = ''
   2880 			break
   2881 
   2882 	if status == 'in tree':
   2883 #:get_current_group_in_tree
   2884 		if cwd.split('/')[-1] == 'tree':
   2885 			group = 'root'
   2886 		else:
   2887 			group = cwd.split('/')[-1]
   2888 #:get_position_from_argv2
   2889 		try:
   2890 			position    = int(sys.argv[2])
   2891 		except:
   2892 			sys.exit('%s is invalid position'%sys.argv[2])
   2893 #:find_task_at_position
   2894 		if position < 0:
   2895 			sys.exit('Position %d is invalid.'%position)
   2896 		group_tasks = os.listdir(generate_group_path(group))
   2897 		order_id    = baseconvert(position)
   2898 		tid         = ''
   2899 		for t in group_tasks:
   2900 			# find exact match
   2901 			if order_id == t[:ORDER_ID_LENGTH]:
   2902 				tid = t[ORDER_ID_LENGTH:]
   2903 		if not tid:
   2904 			sys.exit('Position %d does not exist.'%position)
   2905 		sys.argv[2] = tid
   2906 
   2907 	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   2908 #:tab1_find_task_in_selected_databases_and_setup_data_location
   2909 	if sys.argv[2] == 'root':
   2910 		#set_default_database
   2911 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   2912 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   2913 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2914 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2915 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2916 		if not os.path.exists(edi_core.data_location):
   2917 			sys.exit('%s is unreachable.'%edi_core.data_location)
   2918 	else:
   2919 		for path in edi_core.selected_path:
   2920 			edi_core.data_location        = os.path.expanduser(path)
   2921 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2922 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2923 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2924 
   2925 			if not os.path.exists(edi_core.data_location):
   2926 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   2927 			tasks = os.listdir(edi_core.data_location_tasks)
   2928 			if sys.argv[2] in tasks:
   2929 				break
   2930 	# Verify that task tid is in database
   2931 	tasks = os.listdir(edi_core.data_location_tasks)
   2932 	if not sys.argv[2] in tasks:
   2933 		sys.exit('%s not found.'%sys.argv[2])
   2934 	if len(sys.argv)<4:
   2935 		color = get_forground_color(sys.argv[2])
   2936 		print '%d,%d,%d,%d' % (color[0],color[1],color[2],color[3])
   2937 	if len(sys.argv)==4:
   2938 		set_forground_color(sys.argv[2],sys.argv[3])
   2939 
   2940 ## set or show background color
   2941 #  @ingroup EDI_CLI
   2942 def bc_cli():
   2943 	if len(sys.argv) < 3:
   2944 		sys.exit('Too little parameters.')
   2945 	# Figure out if the command is run in the tree
   2946 #:figure_out_if_in_tree
   2947 	status        = ''
   2948 	cwd           = os.path.realpath(os.getcwd())
   2949 	#loop_on_selected_databases
   2950 	z             = zip(edi_core.selected, edi_core.selected_path)
   2951 	for d,path in z:
   2952 		edi_core.data_location        = os.path.expanduser(path)
   2953 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   2954 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   2955 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   2956 
   2957 		# check path from left
   2958 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   2959 		if real_tree_path == cwd[:len(real_tree_path)]:
   2960 			status = 'in tree'
   2961 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   2962 			break
   2963 
   2964 #:find_task_sysargv2_in_selected_databases
   2965 	# the goal for this code is to reset status when a tid is an existing task
   2966 	# when parameter is taskid, it doesnt matter if cwd is in tree
   2967 	# find task in selected databases
   2968 	for path in edi_core.selected_path:
   2969 		data_location        = os.path.expanduser(path)
   2970 		data_location_tasks  = '%s/tasks'%data_location
   2971 
   2972 		if not os.path.exists(data_location):
   2973 			sys.exit('%s is unreachable.'%path)
   2974 		tasks = os.listdir(data_location_tasks)
   2975 		if sys.argv[2] in tasks:
   2976 			# found task, setup database below
   2977 			status = ''
   2978 			break
   2979 
   2980 	if status == 'in tree':
   2981 #:get_current_group_in_tree
   2982 		if cwd.split('/')[-1] == 'tree':
   2983 			group = 'root'
   2984 		else:
   2985 			group = cwd.split('/')[-1]
   2986 #:get_position_from_argv2
   2987 		try:
   2988 			position    = int(sys.argv[2])
   2989 		except:
   2990 			sys.exit('%s is invalid position'%sys.argv[2])
   2991 #:find_task_at_position
   2992 		if position < 0:
   2993 			sys.exit('Position %d is invalid.'%position)
   2994 		group_tasks = os.listdir(generate_group_path(group))
   2995 		order_id    = baseconvert(position)
   2996 		tid         = ''
   2997 		for t in group_tasks:
   2998 			# find exact match
   2999 			if order_id == t[:ORDER_ID_LENGTH]:
   3000 				tid = t[ORDER_ID_LENGTH:]
   3001 		if not tid:
   3002 			sys.exit('Position %d does not exist.'%position)
   3003 		sys.argv[2] = tid
   3004 
   3005 	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   3006 #:tab1_find_task_in_selected_databases_and_setup_data_location
   3007 	if sys.argv[2] == 'root':
   3008 		#set_default_database
   3009 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   3010 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   3011 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3012 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3013 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3014 		if not os.path.exists(edi_core.data_location):
   3015 			sys.exit('%s is unreachable.'%edi_core.data_location)
   3016 	else:
   3017 		for path in edi_core.selected_path:
   3018 			edi_core.data_location        = os.path.expanduser(path)
   3019 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3020 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3021 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3022 
   3023 			if not os.path.exists(edi_core.data_location):
   3024 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   3025 			tasks = os.listdir(edi_core.data_location_tasks)
   3026 			if sys.argv[2] in tasks:
   3027 				break
   3028 	# Verify that task tid is in database
   3029 	tasks = os.listdir(edi_core.data_location_tasks)
   3030 	if not sys.argv[2] in tasks:
   3031 		sys.exit('%s not found.'%sys.argv[2])
   3032 	if len(sys.argv)<4:
   3033 		color = get_background_color(sys.argv[2])
   3034 		print '%d,%d,%d,%d' % (color[0],color[1],color[2],color[3])
   3035 	if len(sys.argv)==4:
   3036 		set_background_color(sys.argv[2],sys.argv[3])
   3037 
   3038 ## Create database folder and set path in .easydoneit.ini
   3039 #  @ingroup EDI_CLI
   3040 def createDatabase_cli():
   3041 	if len(sys.argv) == 4:
   3042 		name = sys.argv[2]
   3043 		path = os.path.expanduser(sys.argv[3])
   3044 		if name == 'location':
   3045 			sys.exit('%s is invalid database name.'%name)
   3046 		if (not os.path.exists(os.path.dirname(path))) and (os.path.dirname(path)):
   3047 			# os.path.dirname(path) -- to be able to create a database in current directory
   3048 			sys.exit('%s is unreachable.'%os.path.dirname(path))
   3049 #:load_ini_file
   3050 		f      = open(os.path.expanduser('~/.easydoneit.ini'))
   3051 		# load config from user home
   3052 		config = ConfigParser.ConfigParser()
   3053 		config.readfp(f)
   3054 		f.close()
   3055 		config.set('data',name,path)
   3056 #:save_ini_file
   3057 		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
   3058 		config.write(f)
   3059 		f.close()
   3060 		edi_core.data_location = path
   3061 		init()
   3062 	else:
   3063 		sys.exit('Too little or too many parameters. This command takes 2 parameters: databasename path_to_new_database.')
   3064 
   3065 ## choose or show where to add new tasks
   3066 #  @ingroup EDI_CLI
   3067 def topbot_cli():
   3068 	if len(sys.argv)<3:
   3069 		print 'Add new tasks'
   3070 		print '%s of group' % edi_core.add_top_or_bottom
   3071 	else:
   3072 		if (sys.argv[2]!='bottom') and (sys.argv[2] != 'top'):
   3073 			sys.exit('%s is invalid parameter. Possible values are "top" or "bottom".'%sys.argv[2])
   3074 #:load_ini_file
   3075 		f      = open(os.path.expanduser('~/.easydoneit.ini'))
   3076 		# load config from user home
   3077 		config = ConfigParser.ConfigParser()
   3078 		config.readfp(f)
   3079 		f.close()
   3080 		config.set('locations','add_top_or_bottom',sys.argv[2])
   3081 #:save_ini_file
   3082 		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
   3083 		config.write(f)
   3084 		f.close()
   3085 
   3086 ## print group in md format
   3087 #  @ingroup EDI_CLI
   3088 def in_cli():
   3089 	edi_core.list_option = 'md'
   3090 
   3091 	option = ''
   3092 	if len(sys.argv) > 2:
   3093 		if sys.argv[2] == '-A':
   3094 			# option to create agenda is set
   3095 			option = 'create agenda'
   3096 			del sys.argv[2]
   3097 
   3098 	# Figure out if the command is run in the tree
   3099 #:figure_out_if_in_tree
   3100 	status        = ''
   3101 	cwd           = os.path.realpath(os.getcwd())
   3102 	#loop_on_selected_databases
   3103 	z             = zip(edi_core.selected, edi_core.selected_path)
   3104 	for d,path in z:
   3105 		edi_core.data_location        = os.path.expanduser(path)
   3106 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3107 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3108 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3109 
   3110 		# check path from left
   3111 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   3112 		if real_tree_path == cwd[:len(real_tree_path)]:
   3113 			status = 'in tree'
   3114 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   3115 			break
   3116 
   3117 	if len(sys.argv) == 2:
   3118 		# no parameter - just command
   3119 		# select current group when in tree
   3120 		if status == 'in tree':
   3121 			#get_current_group_in_tree
   3122 			if cwd.split('/')[-1] == 'tree':
   3123 				group = 'root'
   3124 			else:
   3125 				group = cwd.split('/')[-1]
   3126 			#end
   3127 
   3128 			task_attributes = list_group(group)
   3129 			if group == 'root':
   3130 				# for root, first task is the title in the md document
   3131 				task_attributes[0]['head'] = 'head group'
   3132 			if option == 'create agenda':
   3133 				# Generate agenda
   3134 				for t in task_attributes[1:]:
   3135 					if t['head'] != 'empty line':
   3136 						edi_core.agenda.append('%3d - %s %s'%(t['position'],t['group'],t['title']))
   3137 			print_list(task_attributes)
   3138 			return
   3139 		else:
   3140 			# default group
   3141 			group = 'root'
   3142 		sys.argv.append(group)
   3143 		# change status because there is no position parameter, no need to search for tid at given position
   3144 		status = ''
   3145 
   3146 #:find_task_sysargv2_in_selected_databases
   3147 	# the goal for this code is to reset status when a tid is an existing task
   3148 	# when parameter is taskid, it doesnt matter if cwd is in tree
   3149 	# find task in selected databases
   3150 	for path in edi_core.selected_path:
   3151 		data_location        = os.path.expanduser(path)
   3152 		data_location_tasks  = '%s/tasks'%data_location
   3153 
   3154 		if not os.path.exists(data_location):
   3155 			sys.exit('%s is unreachable.'%path)
   3156 		tasks = os.listdir(data_location_tasks)
   3157 		if sys.argv[2] in tasks:
   3158 			# found task, setup database below
   3159 			status = ''
   3160 			break
   3161 
   3162 	if status == 'in tree':
   3163 #:get_current_group_in_tree
   3164 		if cwd.split('/')[-1] == 'tree':
   3165 			group = 'root'
   3166 		else:
   3167 			group = cwd.split('/')[-1]
   3168 #:get_position_from_argv2
   3169 		try:
   3170 			position    = int(sys.argv[2])
   3171 		except:
   3172 			sys.exit('%s is invalid position'%sys.argv[2])
   3173 #:find_task_at_position
   3174 		if position < 0:
   3175 			sys.exit('Position %d is invalid.'%position)
   3176 		group_tasks = os.listdir(generate_group_path(group))
   3177 		order_id    = baseconvert(position)
   3178 		tid         = ''
   3179 		for t in group_tasks:
   3180 			# find exact match
   3181 			if order_id == t[:ORDER_ID_LENGTH]:
   3182 				tid = t[ORDER_ID_LENGTH:]
   3183 		if not tid:
   3184 			sys.exit('Position %d does not exist.'%position)
   3185 		sys.argv[2] = tid
   3186 
   3187 	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   3188 #:tab1_find_task_in_selected_databases_and_setup_data_location
   3189 	if sys.argv[2] == 'root':
   3190 		#set_default_database
   3191 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   3192 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   3193 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3194 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3195 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3196 		if not os.path.exists(edi_core.data_location):
   3197 			sys.exit('%s is unreachable.'%edi_core.data_location)
   3198 	else:
   3199 		for path in edi_core.selected_path:
   3200 			edi_core.data_location        = os.path.expanduser(path)
   3201 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3202 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3203 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3204 
   3205 			if not os.path.exists(edi_core.data_location):
   3206 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   3207 			tasks = os.listdir(edi_core.data_location_tasks)
   3208 			if sys.argv[2] in tasks:
   3209 				break
   3210 	# Verify that task tid is in database
   3211 	if not is_this_task_a_group(sys.argv[2]):
   3212 		sys.exit('%s is not a group.'%sys.argv[2])
   3213 
   3214 	task_attributes = list_group(sys.argv[2])
   3215 	if sys.argv[2] == 'root':
   3216 		# for root, first task is the title in the md document
   3217 		task_attributes[0]['head'] = 'head group'
   3218 	if option == 'create agenda':
   3219 		# Generate agenda
   3220 		for t in task_attributes[1:]:
   3221 			if t['head'] != 'empty line':
   3222 				edi_core.agenda.append('%3d - %s %s'%(t['position'],t['group'],t['title']))
   3223 	print_list(task_attributes)
   3224 
   3225 ## print group in reStructuredText format
   3226 #  @ingroup EDI_CLI
   3227 def re_cli():
   3228 	edi_core.list_option = 'rst'
   3229 
   3230 	option = ''
   3231 	if len(sys.argv) > 2:
   3232 		if sys.argv[2] == '-A':
   3233 			# option to create agenda is set
   3234 			option = 'create agenda'
   3235 			del sys.argv[2]
   3236 
   3237 	# Figure out if the command is run in the tree
   3238 #:figure_out_if_in_tree
   3239 	status        = ''
   3240 	cwd           = os.path.realpath(os.getcwd())
   3241 	#loop_on_selected_databases
   3242 	z             = zip(edi_core.selected, edi_core.selected_path)
   3243 	for d,path in z:
   3244 		edi_core.data_location        = os.path.expanduser(path)
   3245 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3246 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3247 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3248 
   3249 		# check path from left
   3250 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   3251 		if real_tree_path == cwd[:len(real_tree_path)]:
   3252 			status = 'in tree'
   3253 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   3254 			break
   3255 
   3256 	if len(sys.argv) == 2:
   3257 		# no parameter - just command
   3258 		# select current group when in tree
   3259 		if status == 'in tree':
   3260 			#get_current_group_in_tree
   3261 			if cwd.split('/')[-1] == 'tree':
   3262 				group = 'root'
   3263 			else:
   3264 				group = cwd.split('/')[-1]
   3265 			#end
   3266 
   3267 			task_attributes = list_group(group)
   3268 			if group == 'root':
   3269 				# for root, first task is the title in the rst document
   3270 				task_attributes[0]['head'] = 'head group'
   3271 			if option == 'create agenda':
   3272 				# Generate agenda
   3273 				for t in task_attributes[1:]:
   3274 					if t['head'] != 'empty line':
   3275 						# keep only title
   3276 						edi_core.agenda.append('#. %s'%t['title'])
   3277 			print_list(task_attributes)
   3278 			return
   3279 		else:
   3280 			# default group
   3281 			group = 'root'
   3282 		sys.argv.append(group)
   3283 		# change status because there is no position parameter, no need to search for tid at given position
   3284 		status = ''
   3285 
   3286 #:find_task_sysargv2_in_selected_databases
   3287 	# the goal for this code is to reset status when a tid is an existing task
   3288 	# when parameter is taskid, it doesnt matter if cwd is in tree
   3289 	# find task in selected databases
   3290 	for path in edi_core.selected_path:
   3291 		data_location        = os.path.expanduser(path)
   3292 		data_location_tasks  = '%s/tasks'%data_location
   3293 
   3294 		if not os.path.exists(data_location):
   3295 			sys.exit('%s is unreachable.'%path)
   3296 		tasks = os.listdir(data_location_tasks)
   3297 		if sys.argv[2] in tasks:
   3298 			# found task, setup database below
   3299 			status = ''
   3300 			break
   3301 
   3302 	if status == 'in tree':
   3303 #:get_current_group_in_tree
   3304 		if cwd.split('/')[-1] == 'tree':
   3305 			group = 'root'
   3306 		else:
   3307 			group = cwd.split('/')[-1]
   3308 #:get_position_from_argv2
   3309 		try:
   3310 			position    = int(sys.argv[2])
   3311 		except:
   3312 			sys.exit('%s is invalid position'%sys.argv[2])
   3313 #:find_task_at_position
   3314 		if position < 0:
   3315 			sys.exit('Position %d is invalid.'%position)
   3316 		group_tasks = os.listdir(generate_group_path(group))
   3317 		order_id    = baseconvert(position)
   3318 		tid         = ''
   3319 		for t in group_tasks:
   3320 			# find exact match
   3321 			if order_id == t[:ORDER_ID_LENGTH]:
   3322 				tid = t[ORDER_ID_LENGTH:]
   3323 		if not tid:
   3324 			sys.exit('Position %d does not exist.'%position)
   3325 		sys.argv[2] = tid
   3326 
   3327 	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   3328 #:tab1_find_task_in_selected_databases_and_setup_data_location
   3329 	if sys.argv[2] == 'root':
   3330 		#set_default_database
   3331 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   3332 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   3333 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3334 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3335 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3336 		if not os.path.exists(edi_core.data_location):
   3337 			sys.exit('%s is unreachable.'%edi_core.data_location)
   3338 	else:
   3339 		for path in edi_core.selected_path:
   3340 			edi_core.data_location        = os.path.expanduser(path)
   3341 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3342 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3343 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3344 
   3345 			if not os.path.exists(edi_core.data_location):
   3346 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   3347 			tasks = os.listdir(edi_core.data_location_tasks)
   3348 			if sys.argv[2] in tasks:
   3349 				break
   3350 	# Verify that task tid is in database
   3351 	if not is_this_task_a_group(sys.argv[2]):
   3352 		sys.exit('%s is not a group.'%sys.argv[2])
   3353 
   3354 	task_attributes = list_group(sys.argv[2])
   3355 	if sys.argv[2] == 'root':
   3356 		# for root, first task is the title in the rst document
   3357 		task_attributes[0]['head'] = 'head group'
   3358 	if option == 'create agenda':
   3359 		# Generate agenda
   3360 		for t in task_attributes[1:]:
   3361 			if t['head'] != 'empty line':
   3362 				# keep only title
   3363 				edi_core.agenda.append('#. %s'%t['title'])
   3364 	print_list(task_attributes)
   3365 
   3366 ## show trees
   3367 #  @ingroup EDI_CLI
   3368 # print all trees: group tids and titles
   3369 def show_trees_cli():
   3370 
   3371 #:loop_on_selected_databases
   3372 		z = zip(edi_core.selected, edi_core.selected_path)
   3373 		for d,path in z:
   3374 			print '%s - %s' % (d,path)
   3375 			edi_core.data_location        = os.path.expanduser(path)
   3376 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3377 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3378 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3379 			if not os.path.exists(edi_core.data_location):
   3380 				sys.exit('%s is unreachable.'%edi_core.data_location)
   3381 			print ''.join(show_tree())
   3382 
   3383 ## zip database
   3384 #  @ingroup EDI_CLI
   3385 # The path parameter is optional
   3386 # When 2 parameters are given, run data function instead.
   3387 def zip_cli():
   3388 
   3389 	if len(sys.argv) < 3:
   3390 		data()
   3391 		return
   3392 	if len(sys.argv) == 3:
   3393 		# path is current directory
   3394 		zip_path = '.'
   3395 	else:
   3396 		zip_path = sys.argv[3]
   3397 	database_name = sys.argv[2]
   3398 
   3399 	# Verify parameters
   3400 	if not database_name in edi_core.selected:
   3401 		sys.exit('%s database is not selected.'%database_name)
   3402 	if not os.path.exists(zip_path):
   3403 		sys.exit('%s is unreachable.'%zip_path)
   3404 
   3405 	# get database system path
   3406 	z = dict(zip(edi_core.selected, edi_core.selected_path))
   3407 
   3408 	# Verify parameters
   3409 	if not os.path.exists(z[database_name]):
   3410 		sys.exit('%s is unreachable.'%z[database_name])
   3411 
   3412 	print 'zipped:      %s' % database_name
   3413 	print 'system path: %s' % z[database_name]
   3414 	print 'target:      %s/%s.tar.bz2' % (zip_path, database_name)
   3415 	print
   3416 	#print    ('tar -c %s | bzip2 -9 > %s/%s.tar.bz2'%(z[database_name], zip_path, database_name))
   3417 	os.system('tar -cj %s > %s/%s.tar.bz2'%(z[database_name], zip_path, database_name))
   3418 
   3419 ## list autolink groups or set autolink groups
   3420 #  @ingroup EDI_CLI
   3421 def autolink_cli():
   3422 	if len(sys.argv)<3:
   3423 		print 'Autolink groups'
   3424 		if not edi_core.autolink:
   3425 			print 'Empty'
   3426 		else:
   3427 			print ','.join(edi_core.autolink)
   3428 			print
   3429 			print '\n'.join(edi_core.autolink)
   3430 	if len(sys.argv)==3:
   3431 #:load_ini_file
   3432 		f      = open(os.path.expanduser('~/.easydoneit.ini'))
   3433 		# load config from user home
   3434 		config = ConfigParser.ConfigParser()
   3435 		config.readfp(f)
   3436 		f.close()
   3437 		config.set('locations','autolink',sys.argv[2])
   3438 #:save_ini_file
   3439 		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
   3440 		config.write(f)
   3441 		f.close()
   3442 
   3443 ## convert empty group to task
   3444 #  @ingroup EDI_CLI
   3445 def cv_cli():
   3446 	if len(sys.argv) < 3:
   3447 		sys.exit('Too little parameters.')
   3448 	# Figure out if the command is run in the tree
   3449 #:figure_out_if_in_tree
   3450 	status        = ''
   3451 	cwd           = os.path.realpath(os.getcwd())
   3452 	#loop_on_selected_databases
   3453 	z             = zip(edi_core.selected, edi_core.selected_path)
   3454 	for d,path in z:
   3455 		edi_core.data_location        = os.path.expanduser(path)
   3456 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3457 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3458 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3459 
   3460 		# check path from left
   3461 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   3462 		if real_tree_path == cwd[:len(real_tree_path)]:
   3463 			status = 'in tree'
   3464 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   3465 			break
   3466 
   3467 #:find_task_sysargv2_in_selected_databases
   3468 	# the goal for this code is to reset status when a tid is an existing task
   3469 	# when parameter is taskid, it doesnt matter if cwd is in tree
   3470 	# find task in selected databases
   3471 	for path in edi_core.selected_path:
   3472 		data_location        = os.path.expanduser(path)
   3473 		data_location_tasks  = '%s/tasks'%data_location
   3474 
   3475 		if not os.path.exists(data_location):
   3476 			sys.exit('%s is unreachable.'%path)
   3477 		tasks = os.listdir(data_location_tasks)
   3478 		if sys.argv[2] in tasks:
   3479 			# found task, setup database below
   3480 			status = ''
   3481 			break
   3482 
   3483 	if status == 'in tree':
   3484 #:get_current_group_in_tree
   3485 		if cwd.split('/')[-1] == 'tree':
   3486 			group = 'root'
   3487 		else:
   3488 			group = cwd.split('/')[-1]
   3489 #:get_position_from_argv2
   3490 		try:
   3491 			position    = int(sys.argv[2])
   3492 		except:
   3493 			sys.exit('%s is invalid position'%sys.argv[2])
   3494 #:find_task_at_position
   3495 		if position < 0:
   3496 			sys.exit('Position %d is invalid.'%position)
   3497 		group_tasks = os.listdir(generate_group_path(group))
   3498 		order_id    = baseconvert(position)
   3499 		tid         = ''
   3500 		for t in group_tasks:
   3501 			# find exact match
   3502 			if order_id == t[:ORDER_ID_LENGTH]:
   3503 				tid = t[ORDER_ID_LENGTH:]
   3504 		if not tid:
   3505 			sys.exit('Position %d does not exist.'%position)
   3506 		sys.argv[2] = tid
   3507 
   3508 	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   3509 #:tab1_find_task_in_selected_databases_and_setup_data_location
   3510 	if sys.argv[2] == 'root':
   3511 		#set_default_database
   3512 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   3513 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   3514 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3515 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3516 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3517 		if not os.path.exists(edi_core.data_location):
   3518 			sys.exit('%s is unreachable.'%edi_core.data_location)
   3519 	else:
   3520 		for path in edi_core.selected_path:
   3521 			edi_core.data_location        = os.path.expanduser(path)
   3522 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3523 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3524 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3525 
   3526 			if not os.path.exists(edi_core.data_location):
   3527 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   3528 			tasks = os.listdir(edi_core.data_location_tasks)
   3529 			if sys.argv[2] in tasks:
   3530 				break
   3531 	# Verify that task tid is not root
   3532 	if sys.argv[2] == 'root':
   3533 		sys.exit('root is invalid group')
   3534 	# Verify that task tid is in database
   3535 	tasks = os.listdir(edi_core.data_location_tasks)
   3536 	if not sys.argv[2] in tasks:
   3537 		sys.exit('%s not found.'%sys.argv[2])
   3538 	if not is_this_task_a_group(sys.argv[2]):
   3539 		sys.exit('%s is not a group.'%sys.argv[2])
   3540 	print '\n'.join(convert_group_to_task(sys.argv[2]))
   3541 
   3542 ## display user name or set user name
   3543 #  @ingroup EDI_CLI
   3544 def user_cli():
   3545 	if len(sys.argv)<3:
   3546 		print 'User name: %s <%s>'%(edi_core.user,edi_core.email)
   3547 	if len(sys.argv)>3:
   3548 		sys.exit('Too many parameters.')
   3549 	if len(sys.argv)==3:
   3550 #:load_ini_file
   3551 		f      = open(os.path.expanduser('~/.easydoneit.ini'))
   3552 		# load config from user home
   3553 		config = ConfigParser.ConfigParser()
   3554 		config.readfp(f)
   3555 		f.close()
   3556 		config.set('settings','username',sys.argv[2])
   3557 #:save_ini_file
   3558 		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
   3559 		config.write(f)
   3560 		f.close()
   3561 
   3562 ## display user email or set user email
   3563 #  @ingroup EDI_CLI
   3564 def email_cli():
   3565 	if len(sys.argv)<3:
   3566 		print 'User name: %s <%s>'%(edi_core.user,edi_core.email)
   3567 	if len(sys.argv)>3:
   3568 		sys.exit('Too many parameters.')
   3569 	if len(sys.argv)==3:
   3570 #:load_ini_file
   3571 		f      = open(os.path.expanduser('~/.easydoneit.ini'))
   3572 		# load config from user home
   3573 		config = ConfigParser.ConfigParser()
   3574 		config.readfp(f)
   3575 		f.close()
   3576 		config.set('settings','useremail',sys.argv[2])
   3577 #:save_ini_file
   3578 		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
   3579 		config.write(f)
   3580 		f.close()
   3581 
   3582 ## show statistics
   3583 #  @ingroup EDI_CLI
   3584 def stats_cli():
   3585 	# Figure out if the command is run in the tree
   3586 #:figure_out_if_in_tree
   3587 	status        = ''
   3588 	cwd           = os.path.realpath(os.getcwd())
   3589 	#loop_on_selected_databases
   3590 	z             = zip(edi_core.selected, edi_core.selected_path)
   3591 	for d,path in z:
   3592 		edi_core.data_location        = os.path.expanduser(path)
   3593 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3594 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3595 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3596 
   3597 		# check path from left
   3598 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   3599 		if real_tree_path == cwd[:len(real_tree_path)]:
   3600 			status = 'in tree'
   3601 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   3602 			break
   3603 
   3604 	# Decide what to execute
   3605 	if len(sys.argv) == 2:
   3606 		tid = 'root'
   3607 		if status:
   3608 			# in tree, set tid to cwd
   3609 			tid = cwd.split('/')[-1]
   3610 			if tid == 'tree':
   3611 				tid = 'root'
   3612 			exe = 'stats in tree'
   3613 		else:
   3614 			exe = 'stats root'
   3615 	else:
   3616 		tid = sys.argv[2]
   3617 
   3618 #:find_task_in_selected_databases_and_setup_data_location
   3619 		if tid == 'root':
   3620 			#set_default_database
   3621 			z = dict(zip(edi_core.selected, edi_core.selected_path))
   3622 			edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   3623 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3624 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3625 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3626 			if not os.path.exists(edi_core.data_location):
   3627 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   3628 		elif tid != 'tree':
   3629 			for path in edi_core.selected_path:
   3630 				edi_core.data_location        = os.path.expanduser(path)
   3631 				edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3632 				edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3633 				edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3634 
   3635 				if not os.path.exists(edi_core.data_location):
   3636 					sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   3637 				tasks = os.listdir(edi_core.data_location_tasks)
   3638 				if tid in tasks:
   3639 					break
   3640 		exe = 'stats parameter'
   3641 
   3642 	if exe == 'stats root':
   3643 #:loop_on_selected_databases
   3644 		z = zip(edi_core.selected, edi_core.selected_path)
   3645 		for d,path in z:
   3646 			print '%s - %s' % (d,path)
   3647 			edi_core.data_location        = os.path.expanduser(path)
   3648 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3649 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3650 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3651 			if not os.path.exists(edi_core.data_location):
   3652 				sys.exit('%s is unreachable.'%edi_core.data_location)
   3653 			print '\n'.join(statistics('for database'))
   3654 	else:
   3655 		if not is_this_task_a_group(tid):
   3656 			sys.exit('Group %s not found.'%tid)
   3657 
   3658 		print '\n'.join(statistics(tid))
   3659 
   3660 ## add many tasks or many groups
   3661 #  @ingroup EDI_CLI
   3662 def many_cli():
   3663 	if len(sys.argv) < 3:
   3664 		sys.exit('Too little parameters.')
   3665 
   3666 #:figure_out_if_in_tree
   3667 	status        = ''
   3668 	cwd           = os.path.realpath(os.getcwd())
   3669 	#loop_on_selected_databases
   3670 	z             = zip(edi_core.selected, edi_core.selected_path)
   3671 	for d,path in z:
   3672 		edi_core.data_location        = os.path.expanduser(path)
   3673 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3674 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3675 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3676 
   3677 		# check path from left
   3678 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   3679 		if real_tree_path == cwd[:len(real_tree_path)]:
   3680 			status = 'in tree'
   3681 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   3682 			break
   3683 
   3684 	options                = ''
   3685 	group_parameter_status = 'group is a command line parameter'
   3686 	if len(sys.argv) < 4:
   3687 		# Parameters are: command filename
   3688 		# select current group when in tree
   3689 		if status == 'in tree':
   3690 			#get_current_group_in_tree
   3691 			if cwd.split('/')[-1] == 'tree':
   3692 				group = 'root'
   3693 			else:
   3694 				group = cwd.split('/')[-1]
   3695 			#end
   3696 		else:
   3697 			# default group
   3698 			group = 'root'
   3699 		group_parameter_status = 'edi selected group'
   3700 
   3701 		text_file = sys.argv[2]
   3702 	else:
   3703 		if ((sys.argv[2] == '-1') or (sys.argv[2] == '-g')) and len(sys.argv) == 4:
   3704 			options   = sys.argv[2]
   3705 			text_file = sys.argv[3]
   3706 			# select current group when in tree
   3707 			if status == 'in tree':
   3708 				#get_current_group_in_tree
   3709 				if cwd.split('/')[-1] == 'tree':
   3710 					group = 'root'
   3711 				else:
   3712 					group = cwd.split('/')[-1]
   3713 				#end
   3714 			else:
   3715 				# default group
   3716 				group = 'root'
   3717 			group_parameter_status = 'edi selected group'
   3718 		if ((sys.argv[2] == '-1') or (sys.argv[2] == '-g')) and len(sys.argv) == 5:
   3719 			options   = sys.argv[2]
   3720 			group     = sys.argv[3]
   3721 			text_file = sys.argv[4]
   3722 		if ((sys.argv[2] != '-1') and (sys.argv[2] != '-g')):
   3723 			group     = sys.argv[2]
   3724 			text_file = sys.argv[3]
   3725 	if not options:
   3726 		exe = 'add'
   3727 	else:
   3728 		if options == '-1':
   3729 			# option -1 adds one task per line in text_file
   3730 			exe = 'add one task per line'
   3731 		elif options == '-g':
   3732 			# option -F stores text_file filename in first line of description
   3733 			exe = 'add groups from text file'
   3734 
   3735 	if (group == 'root') and (not status):
   3736 		# set default database when group is root and cwd not in tree
   3737 #:set_default_database
   3738 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   3739 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   3740 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3741 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3742 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3743 		if not os.path.exists(edi_core.data_location):
   3744 			sys.exit('%s is unreachable.'%edi_core.data_location)
   3745 	if (group != 'root') and ((not status) or (group_parameter_status == 'group is a command line parameter')):
   3746 #:find_group_in_selected_databases_and_setup_data_location
   3747 		for path in edi_core.selected_path:
   3748 			edi_core.data_location        = os.path.expanduser(path)
   3749 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3750 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3751 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3752 
   3753 			if not os.path.exists(edi_core.data_location):
   3754 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   3755 			groups = os.listdir(edi_core.data_location_groups)
   3756 			if group in groups:
   3757 				break
   3758 
   3759 	if not is_this_task_a_group(group):
   3760 		sys.exit('%s is not a group.'%group)
   3761 
   3762 	if not os.path.exists(text_file):
   3763 		sys.exit('%s unreachable file.'%text_file)
   3764 
   3765 	if exe == 'add':
   3766 		print add_many_tasks(group,text_file)
   3767 	if exe == 'add one task per line':
   3768 		print add_many_one_line_tasks(group,text_file)
   3769 	if exe == 'add groups from text file':
   3770 		print add_many_groups_from_text(group,text_file)
   3771 
   3772 ## demo to show how to use Easydoneit CLI
   3773 #  @ingroup EDI_CLI
   3774 def demo_cli():
   3775 	print '# Easydoneit CLI - Demo'
   3776 	# print (), to print without a newline
   3777 	print ('#'),
   3778 #:edi_version
   3779 	f = open('%s/VERSION'%os.path.abspath(os.path.dirname(sys.argv[0])))
   3780 	v = f.readline()
   3781 	f.close()
   3782 	print 'Version %s'%v
   3783 
   3784 	print '''
   3785 # Run the commands below in a terminal
   3786 
   3787 # create the demo database
   3788 edi createDatabase easydoneit_cli_demo ~/easydoneit_cli_demo
   3789 
   3790 # show selected databases - SAVE THIS STRING
   3791 edi select
   3792 
   3793 # show default database - SAVE THIS STRING
   3794 edi default
   3795 
   3796 # select demo database
   3797 edi select easydoneit_cli_demo
   3798 
   3799 # demo database is default
   3800 edi default easydoneit_cli_demo
   3801 
   3802 # the configuration file is in your home, change text editor if you dont use VI
   3803 cat ~/.easydoneit.ini
   3804 
   3805 # create a task in default database, type your task in the text editor
   3806 edi cr
   3807 
   3808 # list tasks
   3809 edi ls
   3810 
   3811 # add task directly from command line
   3812 edi add -t demo_task_1
   3813 edi add -t 'demo task 2 - string with spaces'
   3814 edi ls
   3815 
   3816 # tasks can be added on the top of the list
   3817 edi topbot top
   3818 
   3819 # add task from file
   3820 echo 'demo task 3' > ~/demo_3.txt
   3821 edi add ~/demo_3.txt
   3822 rm ~/demo_3.txt
   3823 edi ls
   3824 
   3825 # choose to add tasks at the bottom
   3826 edi topbot bottom
   3827 
   3828 # it is simpler to use Easydoneit CLI in the tree
   3829 cd ~/easydoneit_cli_demo/tree
   3830 edi ls
   3831 
   3832 # create a group using position
   3833 edi mkdir 0
   3834 
   3835 # background color
   3836 edi bc 0 230,230,230,255
   3837 
   3838 # change order, moves task at position 0 to position 2
   3839 edi order 0 2
   3840 
   3841 # change state to done, pending and inactive
   3842 edi set 0 1
   3843 edi set 1 3
   3844 edi set 2 4
   3845 edi ls
   3846 
   3847 # display the complete tree of groups
   3848 edi st
   3849 
   3850 # filter out done tasks
   3851 edi stfi done disable
   3852 edi ls
   3853 
   3854 # search
   3855 edi search demo
   3856 
   3857 # delete task
   3858 edi rm 1
   3859 
   3860 # display system path for a task
   3861 edi path 2
   3862 
   3863 # generate html
   3864 edi html
   3865 
   3866 # generate reStructuredText (rst)
   3867 edi re
   3868 
   3869 # zip
   3870 edi zip easydoneit_cli_demo ~/
   3871 
   3872 # delete database, RESELECT YOUR DATABASES WITH edi select BEFORE RUNNING THE COMMANDS BELOW
   3873 cd -
   3874 edi data -d easydoneit_cli_demo
   3875 edi data
   3876 
   3877 # remove database zip
   3878 rm ~/easydoneit_cli_demo.tar.bz2
   3879 
   3880 # end
   3881 	'''
   3882 
   3883 ## set list of group for edi ls -L, -La and -Lx options
   3884 #  @ingroup EDI_CLI
   3885 def list_cli():
   3886 	if len(sys.argv)<3:
   3887 		print 'list of groups'
   3888 		if not edi_core.list_of_groups:
   3889 			print 'Empty'
   3890 		else:
   3891 			print ','.join(edi_core.list_of_groups)
   3892 			print
   3893 			print '\n'.join(edi_core.list_of_groups)
   3894 	if len(sys.argv)==3:
   3895 #:load_ini_file
   3896 		f      = open(os.path.expanduser('~/.easydoneit.ini'))
   3897 		# load config from user home
   3898 		config = ConfigParser.ConfigParser()
   3899 		config.readfp(f)
   3900 		f.close()
   3901 		config.set('locations','list',sys.argv[2])
   3902 #:save_ini_file
   3903 		f      = open(os.path.expanduser('~/.easydoneit.ini'),'w')
   3904 		config.write(f)
   3905 		f.close()
   3906 
   3907 ## copy database sys.argv[2] to database sys.argv[3]
   3908 #  @ingroup EDI_CLI
   3909 def merge_cli():
   3910 	if len(sys.argv) < 4:
   3911 		sys.exit('Too little parameters.')
   3912 
   3913 	# set source path (argv 2)
   3914 	path             = ''
   3915 	if os.path.exists(sys.argv[2]):
   3916 		path = sys.argv[2]
   3917 	if not path:
   3918 		# argv 2 could be a database name
   3919 		dbs  = dict(edi_core.databases)
   3920 		if sys.argv[2] in dbs.keys():
   3921 			path = dbs[sys.argv[2]]
   3922 	if not path:
   3923 		sys.exit('Source database %s not found.'%sys.argv[2])
   3924 
   3925 	# check source database structure
   3926 	directories      = ['tasks', 'groups', 'tree']
   3927 
   3928 	status = 'source database structure ok'
   3929 	for d in directories:
   3930 		directory = '%s/%s'%(path, d)
   3931 		if not os.path.exists(directory):
   3932 			print 'Missing %s'%directory
   3933 			status = 'missing directories in source database'
   3934 	if status == 'missing directories in source database':
   3935 		sys.exit('Invalid source database %s'%path)
   3936 
   3937 	# check destination database
   3938 	if not sys.argv[3] in edi_core.selected:
   3939 		sys.exit('%s database not selected.'%sys.argv[3])
   3940 
   3941 	s                = dict(zip(edi_core.selected, edi_core.selected_path))
   3942 	destination_path = s[sys.argv[3]]
   3943 
   3944 	# copy database
   3945 	for d in directories:
   3946 		directory  = '%s/%s'%(path, d)
   3947 		ddirectory = '%s/%s'%(destination_path, d)
   3948 		os.system('cp -R %s/* %s'%(directory,ddirectory))
   3949 
   3950 
   3951 ## copy media sys.argv[3] to task sys.argv[2]
   3952 #  @ingroup EDI_CLI
   3953 def media_cli():
   3954 	if len(sys.argv) < 3:
   3955 		sys.exit('Too little parameters.')
   3956 	# Figure out if the command is run in the tree
   3957 #:figure_out_if_in_tree
   3958 	status        = ''
   3959 	cwd           = os.path.realpath(os.getcwd())
   3960 	#loop_on_selected_databases
   3961 	z             = zip(edi_core.selected, edi_core.selected_path)
   3962 	for d,path in z:
   3963 		edi_core.data_location        = os.path.expanduser(path)
   3964 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   3965 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   3966 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   3967 
   3968 		# check path from left
   3969 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   3970 		if real_tree_path == cwd[:len(real_tree_path)]:
   3971 			status = 'in tree'
   3972 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   3973 			break
   3974 
   3975 #:find_task_sysargv2_in_selected_databases
   3976 	# the goal for this code is to reset status when a tid is an existing task
   3977 	# when parameter is taskid, it doesnt matter if cwd is in tree
   3978 	# find task in selected databases
   3979 	for path in edi_core.selected_path:
   3980 		data_location        = os.path.expanduser(path)
   3981 		data_location_tasks  = '%s/tasks'%data_location
   3982 
   3983 		if not os.path.exists(data_location):
   3984 			sys.exit('%s is unreachable.'%path)
   3985 		tasks = os.listdir(data_location_tasks)
   3986 		if sys.argv[2] in tasks:
   3987 			# found task, setup database below
   3988 			status = ''
   3989 			break
   3990 
   3991 	if status == 'in tree':
   3992 #:get_current_group_in_tree
   3993 		if cwd.split('/')[-1] == 'tree':
   3994 			group = 'root'
   3995 		else:
   3996 			group = cwd.split('/')[-1]
   3997 #:get_position_from_argv2
   3998 		try:
   3999 			position    = int(sys.argv[2])
   4000 		except:
   4001 			sys.exit('%s is invalid position'%sys.argv[2])
   4002 #:find_task_at_position
   4003 		if position < 0:
   4004 			sys.exit('Position %d is invalid.'%position)
   4005 		group_tasks = os.listdir(generate_group_path(group))
   4006 		order_id    = baseconvert(position)
   4007 		tid         = ''
   4008 		for t in group_tasks:
   4009 			# find exact match
   4010 			if order_id == t[:ORDER_ID_LENGTH]:
   4011 				tid = t[ORDER_ID_LENGTH:]
   4012 		if not tid:
   4013 			sys.exit('Position %d does not exist.'%position)
   4014 		sys.argv[2] = tid
   4015 
   4016 	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   4017 #:tab1_find_task_in_selected_databases_and_setup_data_location
   4018 	if sys.argv[2] == 'root':
   4019 		#set_default_database
   4020 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   4021 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   4022 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   4023 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   4024 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   4025 		if not os.path.exists(edi_core.data_location):
   4026 			sys.exit('%s is unreachable.'%edi_core.data_location)
   4027 	else:
   4028 		for path in edi_core.selected_path:
   4029 			edi_core.data_location        = os.path.expanduser(path)
   4030 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   4031 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   4032 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   4033 
   4034 			if not os.path.exists(edi_core.data_location):
   4035 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   4036 			tasks = os.listdir(edi_core.data_location_tasks)
   4037 			if sys.argv[2] in tasks:
   4038 				break
   4039 	# Verify that task tid is in database
   4040 	tasks = os.listdir(edi_core.data_location_tasks)
   4041 	if not sys.argv[2] in tasks:
   4042 		sys.exit('%s not found.'%sys.argv[2])
   4043 	if len(sys.argv)<4:
   4044 		print '\n'.join(get_media(sys.argv[2]))
   4045 	if len(sys.argv)==4:
   4046 		if not os.path.exists(sys.argv[3]):
   4047 			sys.exit('%s not found.'%sys.argv[3])
   4048 		print set_media(sys.argv[2],sys.argv[3])
   4049 
   4050 
   4051 ## copy attachments sys.argv[3] to task sys.argv[2]
   4052 #  @ingroup EDI_CLI
   4053 def at_cli():
   4054 	if len(sys.argv) < 3:
   4055 		sys.exit('Too little parameters.')
   4056 	# Figure out if the command is run in the tree
   4057 #:figure_out_if_in_tree
   4058 	status        = ''
   4059 	cwd           = os.path.realpath(os.getcwd())
   4060 	#loop_on_selected_databases
   4061 	z             = zip(edi_core.selected, edi_core.selected_path)
   4062 	for d,path in z:
   4063 		edi_core.data_location        = os.path.expanduser(path)
   4064 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   4065 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   4066 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   4067 
   4068 		# check path from left
   4069 		real_tree_path = os.path.realpath(edi_core.data_location_tree)
   4070 		if real_tree_path == cwd[:len(real_tree_path)]:
   4071 			status = 'in tree'
   4072 			p_l    = edi_core.data_location_tree.split('/')[-2:]
   4073 			break
   4074 
   4075 #:find_task_sysargv2_in_selected_databases
   4076 	# the goal for this code is to reset status when a tid is an existing task
   4077 	# when parameter is taskid, it doesnt matter if cwd is in tree
   4078 	# find task in selected databases
   4079 	for path in edi_core.selected_path:
   4080 		data_location        = os.path.expanduser(path)
   4081 		data_location_tasks  = '%s/tasks'%data_location
   4082 
   4083 		if not os.path.exists(data_location):
   4084 			sys.exit('%s is unreachable.'%path)
   4085 		tasks = os.listdir(data_location_tasks)
   4086 		if sys.argv[2] in tasks:
   4087 			# found task, setup database below
   4088 			status = ''
   4089 			break
   4090 
   4091 	if status == 'in tree':
   4092 #:get_current_group_in_tree
   4093 		if cwd.split('/')[-1] == 'tree':
   4094 			group = 'root'
   4095 		else:
   4096 			group = cwd.split('/')[-1]
   4097 #:get_position_from_argv2
   4098 		try:
   4099 			position    = int(sys.argv[2])
   4100 		except:
   4101 			sys.exit('%s is invalid position'%sys.argv[2])
   4102 #:find_task_at_position
   4103 		if position < 0:
   4104 			sys.exit('Position %d is invalid.'%position)
   4105 		group_tasks = os.listdir(generate_group_path(group))
   4106 		order_id    = baseconvert(position)
   4107 		tid         = ''
   4108 		for t in group_tasks:
   4109 			# find exact match
   4110 			if order_id == t[:ORDER_ID_LENGTH]:
   4111 				tid = t[ORDER_ID_LENGTH:]
   4112 		if not tid:
   4113 			sys.exit('Position %d does not exist.'%position)
   4114 		sys.argv[2] = tid
   4115 
   4116 	# cant cover sys.exit('%s is unreachable.'%d) below, exception catched before. Dont add no cover because the code is reused in other functions.
   4117 #:tab1_find_task_in_selected_databases_and_setup_data_location
   4118 	if sys.argv[2] == 'root':
   4119 		#set_default_database
   4120 		z = dict(zip(edi_core.selected, edi_core.selected_path))
   4121 		edi_core.data_location        = os.path.expanduser(z[edi_core.default_add_in])
   4122 		edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   4123 		edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   4124 		edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   4125 		if not os.path.exists(edi_core.data_location):
   4126 			sys.exit('%s is unreachable.'%edi_core.data_location)
   4127 	else:
   4128 		for path in edi_core.selected_path:
   4129 			edi_core.data_location        = os.path.expanduser(path)
   4130 			edi_core.data_location_tasks  = '%s/tasks'%edi_core.data_location
   4131 			edi_core.data_location_groups = '%s/groups'%edi_core.data_location
   4132 			edi_core.data_location_tree   = '%s/tree'%edi_core.data_location
   4133 
   4134 			if not os.path.exists(edi_core.data_location):
   4135 				sys.exit('%s is unreachable.'%edi_core.data_location) #pragma: no cover
   4136 			tasks = os.listdir(edi_core.data_location_tasks)
   4137 			if sys.argv[2] in tasks:
   4138 				break
   4139 	# Verify that task tid is in database
   4140 	tasks = os.listdir(edi_core.data_location_tasks)
   4141 	if not sys.argv[2] in tasks:
   4142 		sys.exit('%s not found.'%sys.argv[2])
   4143 	if len(sys.argv)<4:
   4144 		print '\n'.join(get_attachments(sys.argv[2]))
   4145 	if len(sys.argv)>3:
   4146 		for fn in sys.argv[3:]:
   4147 			if not os.path.exists(fn):
   4148 				sys.exit('%s not found.'%fn)
   4149 		print '\n'.join(set_attachments(sys.argv[2],sys.argv[3:]))
   4150 
   4151 
   4152 ## CLI command functions
   4153 FUNCTIONS    = [help,version,create_task_cli,lsid,add_task_cli,cat,mkdir,show_group_for_task_cli,rm,vi,change_order,set,reset,search,move_task,copy_task,link_task,get_task_path,tree,ls,set_status_filter,data,html_cli,selected_cli,default_cli,cpb_cli,mvb_cli,fc_cli,bc_cli,createDatabase_cli,topbot_cli,in_cli,re_cli,show_trees_cli,zip_cli,autolink_cli,cv_cli,user_cli,email_cli,stats_cli,many_cli,demo_cli,list_cli,merge_cli,media_cli,at_cli]
   4154 
   4155 COMMAND_MAP = dict(zip(COMMANDS,FUNCTIONS))
   4156 
   4157 
   4158 if __name__ == '__main__':
   4159 #:print_command_map
   4160 #:end
   4161 	start() #pragma: no cover
   4162 
   4163 	if len(sys.argv)> 1: #pragma: no cover
   4164 		# remove whitespaces from parameters. ^M can come for scripts
   4165 		for i,a in enumerate(sys.argv[1:]): #pragma: no cover
   4166 			sys.argv[i+1] = a.strip()  #pragma: no cover
   4167 #:not profiler
   4168 		COMMAND_MAP.get(sys.argv[1],Nothing)() #pragma: no cover
   4169 #:else
   4170 #:end
   4171 	else:
   4172 		help() #pragma: no cover
   4173 #:profiler
   4174 #:end