modularized, bugfixes
This commit is contained in:
parent
3a5633603b
commit
40026a3c0d
7 changed files with 191 additions and 186 deletions
6
.context.yaml
Normal file
6
.context.yaml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
files:
|
||||
TODO.md:
|
||||
contexts: []
|
||||
projects:
|
||||
- bokertov
|
||||
tags: []
|
||||
2
orvani/__init__.py
Normal file
2
orvani/__init__.py
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
from .orvani import OrvaniTag
|
||||
from .cmd import main
|
||||
BIN
orvani/__pycache__/orvani.cpython-310.pyc
Normal file
BIN
orvani/__pycache__/orvani.cpython-310.pyc
Normal file
Binary file not shown.
140
orvani/cmd.py
Normal file
140
orvani/cmd.py
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
import os
|
||||
import sys
|
||||
from argparse import ArgumentParser as argp, SUPPRESS, RawTextHelpFormatter as raw
|
||||
from pathlib import Path
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
from orvani import OrvaniTag, CONTEXT_FILE, CACHE_FILE
|
||||
|
||||
def mktable(query: str, index: dict):
|
||||
console = Console()
|
||||
if len(index['found']) > 0:
|
||||
table = Table(title=f"Results for `{query}`")
|
||||
table.add_column("Path", justify="right", style="white", no_wrap=True)
|
||||
table.add_column("Note", style="#cccccc")
|
||||
table.add_column("Projects", justify="center", style="cyan")
|
||||
table.add_column("Contexts", justify="center", style="magenta")
|
||||
table.add_column("Tags", justify="center", style="green")
|
||||
note = tags = projects = contexts = tags = ''
|
||||
for file in index['found']:
|
||||
path = file
|
||||
fc = index['index']['files'][file]
|
||||
if 'note' in fc:
|
||||
note = fc['note']
|
||||
else:
|
||||
note = ''
|
||||
tags = ' '.join(['#' + tag for tag in fc['tags']])
|
||||
projects = ' '.join(['+' + p for p in fc['projects']])
|
||||
contexts = ' '.join(['@' + c for c in fc['contexts']])
|
||||
table.add_row(path, note, projects, contexts, tags)
|
||||
console.print(table)
|
||||
else:
|
||||
console.print(f"No results found for `{query}`", style="red")
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
command_help = """{add,a} FILE [CONTEXT ...]
|
||||
{remove,rem,r} FILE [CONTEXT ...]
|
||||
|
||||
{copy,cp} SOURCE DEST
|
||||
{move,mv} SOURCE DEST
|
||||
{del,rm} FILE
|
||||
|
||||
{clear,c} FILE
|
||||
{clean} PATH
|
||||
|
||||
{list,ls,dir,l} QUERY
|
||||
{listproj,lsprj} QUERY
|
||||
{listcon,lsc} QUERY
|
||||
{listtag,lst} QUERY
|
||||
"""
|
||||
|
||||
p = argp(description="OrvaniTagger", formatter_class=raw)
|
||||
p.add_argument("--not-recursive", "-nr", action="store_false", help="Include subdirectories in search")
|
||||
p.add_argument("--no-file_operation", "-nf", action="store_false", help="Copy/Move/Delete file, not just context")
|
||||
p.add_argument("--path", "-p", action="store", type=str, help="List/search custom path", default='')
|
||||
p.add_argument("--exact", "-e", action="store_true", help="Match exact search term")
|
||||
p.add_argument("--cache", action="store_true", help="Cache index search (useful with deep directory trees)")
|
||||
p.add_argument("--context_filter", "-c", action="store", type=str, help="Filter context", choices=['context', 'project', 'tag'], default=None)
|
||||
p.add_argument("command", nargs="?", default=None, metavar='Command',
|
||||
help=command_help, type=str,
|
||||
choices=[
|
||||
'add', 'a',
|
||||
'remove', 'rem', 'r',
|
||||
'list', 'ls', 'dir', 'l',
|
||||
'copy', 'cp',
|
||||
'move', 'mv',
|
||||
'del', 'rm',
|
||||
'clear', 'c',
|
||||
'listproj', 'lsprj',
|
||||
'listcon', 'lsc',
|
||||
'listtag', 'lst',
|
||||
'clean', 'purge',
|
||||
'read'
|
||||
])
|
||||
p.add_argument("file", nargs="?", type=str, help=SUPPRESS)
|
||||
p.add_argument("context", nargs="*", type=str, help=SUPPRESS)
|
||||
p.print_usage = p.print_help
|
||||
args = p.parse_args()
|
||||
|
||||
orvani = OrvaniTag()
|
||||
|
||||
if args.command in ['add', 'a']:
|
||||
if args.file and args.context:
|
||||
orvani.add(args.file, *args.context)
|
||||
|
||||
elif args.command in ['remove', 'rem', 'r']:
|
||||
if args.file and args.context:
|
||||
orvani.remove(args.file, *args.context)
|
||||
|
||||
elif args.command in ['list', 'ls', 'dir', 'l', 'listproj', 'lsprj', 'lp', 'listcon', 'lsc', 'lc', 'listtag', 'lst', 'lt']:
|
||||
query = [args.file] + args.context
|
||||
if args.command in ['listproj', 'lsprj', 'lp'] or args.context_filter == 'project':
|
||||
args.context_filter = 'projects'
|
||||
if args.command in ['listcon', 'lsc', 'lc'] or args.context_filter == 'context':
|
||||
args.context_filter = 'contexts'
|
||||
if args.command in ['listtag', 'lst', 'lt'] or args.context_filter == 'tag':
|
||||
args.context_filter = 'tags'
|
||||
if query:
|
||||
r = orvani.list(args.path, args.context_filter, args.exact, args.not_recursive, args.cache, *query)
|
||||
mktable(' '.join(sys.argv[1:]), r)
|
||||
|
||||
elif args.command in ['copy', 'cp']:
|
||||
if args.file and args.context:
|
||||
orvani.move(args.file, args.context[0], True, args.no_file_operation)
|
||||
|
||||
elif args.command in ['move', 'mv']:
|
||||
if args.file and args.context:
|
||||
orvani.move(args.file, args.context[0], False, args.no_file_operation)
|
||||
|
||||
elif args.command in ['del', 'rm']:
|
||||
if args.file:
|
||||
orvani.delete(args.file, args.no_file_operation)
|
||||
|
||||
elif args.command in ['purge']:
|
||||
if not args.file:
|
||||
args.file = '.'
|
||||
target = Path(args.file)
|
||||
context_file = target / CONTEXT_FILE
|
||||
cache_file = target / CACHE_FILE
|
||||
context_file.unlink(missing_ok=True)
|
||||
cache_file.unlink(missing_ok=True)
|
||||
if args.not_recursive:
|
||||
for (root,dirs,files) in os.walk(args.file):
|
||||
if dirs:
|
||||
for dir in dirs:
|
||||
rpath = os.path.join(root, dir)
|
||||
Path(CONTEXT_FILE).unlink(missing_ok=True)
|
||||
Path(CACHE_FILE).unlink(missing_ok=True)
|
||||
|
||||
elif args.command in ['clean']:
|
||||
if not args.file:
|
||||
args.file = ''
|
||||
orvani.purge(args.file, args.not_recursive)
|
||||
|
||||
elif args.command in ['read']:
|
||||
orvani.read_meta()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -1,12 +1,7 @@
|
|||
import os
|
||||
import sys
|
||||
import yaml
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from argparse import ArgumentParser as argp, SUPPRESS, RawTextHelpFormatter as raw
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
import frontmatter
|
||||
|
||||
# Defaults
|
||||
|
||||
|
|
@ -73,9 +68,8 @@ class OrvaniTag:
|
|||
y = { 'files' : self.DB }
|
||||
if self.CONFIG:
|
||||
y['config'] = self.CONFIG
|
||||
if Path(self.FILE).is_file():
|
||||
with Path(self.FILE).open('w') as data:
|
||||
yaml.safe_dump(y, data)
|
||||
with Path(self.FILE).open('w+') as data:
|
||||
yaml.safe_dump(y, data)
|
||||
|
||||
|
||||
def __context(self, argv) -> dict:
|
||||
|
|
@ -117,14 +111,15 @@ class OrvaniTag:
|
|||
if target.exists():
|
||||
self.__cd(target.parent.name)
|
||||
context = self.__context(argv)
|
||||
if file in self.DB:
|
||||
if target.name in self.DB:
|
||||
for ctx in self.CTX.keys():
|
||||
if self.CTX[ctx] != None:
|
||||
self.DB[file][ctx] = list(set( self.DB[file][ctx] + context[ctx]))
|
||||
self.DB[target.name][ctx] = list(set( self.DB[target.name][ctx] + context[ctx]))
|
||||
else:
|
||||
self.DB[file][ctx] = context[ctx]
|
||||
if ctx in context:
|
||||
self.DB[target.name][ctx] = context[ctx]
|
||||
else:
|
||||
self.DB.update( { file : context } )
|
||||
self.DB.update( { target.name : context } )
|
||||
self.__save()
|
||||
|
||||
def remove(self, file: str, *argv: str):
|
||||
|
|
@ -241,8 +236,6 @@ class OrvaniTag:
|
|||
"""
|
||||
if path == '':
|
||||
path = './'
|
||||
if not os.path.dirname(path):
|
||||
path += '/'
|
||||
self.__makeindex(path, recursive, cache)
|
||||
result = self.__search(search, exact)
|
||||
return result
|
||||
|
|
@ -272,13 +265,9 @@ class OrvaniTag:
|
|||
recursive (bool): traverse subdirectories
|
||||
|
||||
"""
|
||||
cachefile = os.path.join(path, self.CACHEFILE)
|
||||
if cache and os.path.isfile(cachefile):
|
||||
try:
|
||||
with open(cachefile, 'r') as cache:
|
||||
self.INDEX = yaml.safe_load(cache)
|
||||
except Exception:
|
||||
print('File does not exist')
|
||||
cachefile = Path(path) / self.CACHEFILE
|
||||
if cache and cachefile.is_file():
|
||||
self.INDEX = yaml.safe_load(cachefile.read_text())
|
||||
else:
|
||||
self.__indexfolder(path)
|
||||
if recursive:
|
||||
|
|
@ -288,11 +277,8 @@ class OrvaniTag:
|
|||
rpath = os.path.join(root, dir)
|
||||
self.__indexfolder(rpath)
|
||||
if cache:
|
||||
try:
|
||||
with open(cachefile, 'w+') as data:
|
||||
yaml.dump(self.INDEX, data)
|
||||
except Exception:
|
||||
print('File write error')
|
||||
with open(cachefile, 'w+') as data:
|
||||
yaml.dump(self.INDEX, data)
|
||||
|
||||
def __indexfolder(self, sub: str):
|
||||
"""
|
||||
|
|
@ -301,19 +287,21 @@ class OrvaniTag:
|
|||
sub (str): path of folder
|
||||
|
||||
"""
|
||||
if os.path.dirname(sub):
|
||||
self.__cd(sub)
|
||||
target = Path(sub)
|
||||
if target.is_dir():
|
||||
self.__cd(target.name)
|
||||
if self.DB:
|
||||
for file in self.DB.keys():
|
||||
path = os.path.join(sub, file)
|
||||
self.INDEX['files'].update( { path : self.DB[file]} )
|
||||
for ctx in self.CTX.keys():
|
||||
for item in self.DB[file][ctx]:
|
||||
filelist = [path]
|
||||
if ctx in self.INDEX:
|
||||
if item in self.INDEX[ctx]:
|
||||
filelist += self.INDEX[ctx][item]
|
||||
self.INDEX[ctx][item] = filelist
|
||||
if ctx in self.DB[file]:
|
||||
for item in self.DB[file][ctx]:
|
||||
filelist = [path]
|
||||
if ctx in self.INDEX:
|
||||
if item in self.INDEX[ctx]:
|
||||
filelist += self.INDEX[ctx][item]
|
||||
self.INDEX[ctx][item] = filelist
|
||||
|
||||
def __search(self, search, filter: str=None, exact:bool=False):
|
||||
"""
|
||||
|
|
@ -335,25 +323,17 @@ class OrvaniTag:
|
|||
for context in self.INDEX[ctx]:
|
||||
if filter and not filter == ctx:
|
||||
continue
|
||||
for q in query[ctx]:
|
||||
if exact:
|
||||
if q == context:
|
||||
if self.INDEX[ctx][context] not in ret[ctx]:
|
||||
ret[ctx] += self.INDEX[ctx][context]
|
||||
else:
|
||||
if q in context:
|
||||
if self.INDEX[ctx][context] not in ret[ctx]:
|
||||
ret[ctx] += self.INDEX[ctx][context]
|
||||
if exact:
|
||||
if 'note' in query and query['note'] == context:
|
||||
if self.INDEX[ctx][context] not in ret['note']:
|
||||
ret['note'] += self.INDEX[ctx][context]
|
||||
else:
|
||||
if 'note' in query and query['note'] in context:
|
||||
if self.INDEX[ctx][context] not in ret['note']:
|
||||
ret['note'] += self.INDEX[ctx][context]
|
||||
if ctx in query:
|
||||
for q in query[ctx]:
|
||||
if exact:
|
||||
if q == context:
|
||||
if self.INDEX[ctx][context] not in ret[ctx]:
|
||||
ret[ctx] += self.INDEX[ctx][context]
|
||||
else:
|
||||
if q in context:
|
||||
if self.INDEX[ctx][context] not in ret[ctx]:
|
||||
ret[ctx] += self.INDEX[ctx][context]
|
||||
ret[ctx] = list(set(ret[ctx]))
|
||||
ret['note'] = list(set(ret['note']))
|
||||
if len(search) > 1:
|
||||
result['found'] = sorted(list(set(self.__intersect(ret))), key=lambda x: x.count('/'))
|
||||
else:
|
||||
|
|
@ -376,137 +356,4 @@ class OrvaniTag:
|
|||
def read_meta(self):
|
||||
for callback in self.META_IN:
|
||||
entry = callback(self.CONFIG, self.DB)
|
||||
print(entry)
|
||||
|
||||
def mktable(query: str, index: dict):
|
||||
console = Console()
|
||||
if len(index['found']) > 0:
|
||||
table = Table(title=f"Results for `{query}`")
|
||||
table.add_column("Path", justify="right", style="white", no_wrap=True)
|
||||
table.add_column("Note", style="#cccccc")
|
||||
table.add_column("Projects", justify="center", style="cyan")
|
||||
table.add_column("Contexts", justify="center", style="magenta")
|
||||
table.add_column("Tags", justify="center", style="green")
|
||||
note = tags = projects = contexts = tags = ''
|
||||
for file in index['found']:
|
||||
path = file
|
||||
fc = index['index']['files'][file]
|
||||
if 'note' in fc:
|
||||
note = fc['note']
|
||||
else:
|
||||
note = ''
|
||||
tags = ' '.join(['#' + tag for tag in fc['tags']])
|
||||
projects = ' '.join(['+' + p for p in fc['projects']])
|
||||
contexts = ' '.join(['@' + c for c in fc['contexts']])
|
||||
table.add_row(path, note, projects, contexts, tags)
|
||||
console.print(table)
|
||||
else:
|
||||
console.print(f"No results found for `{query}`", style="red")
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
command_help = """{add,a} FILE [CONTEXT ...]
|
||||
{remove,rem,r} FILE [CONTEXT ...]
|
||||
|
||||
{copy,cp} SOURCE DEST
|
||||
{move,mv} SOURCE DEST
|
||||
{del,rm} FILE
|
||||
|
||||
{clear,c} FILE
|
||||
{clean} PATH
|
||||
|
||||
{list,ls,dir,l} QUERY
|
||||
{listproj,lsprj} QUERY
|
||||
{listcon,lsc} QUERY
|
||||
{listtag,lst} QUERY
|
||||
"""
|
||||
|
||||
p = argp(description="OrvaniTagger", formatter_class=raw)
|
||||
p.add_argument("--not-recursive", "-nr", action="store_false", help="Include subdirectories in search")
|
||||
p.add_argument("--no-file_operation", "-nf", action="store_false", help="Copy/Move/Delete file, not just context")
|
||||
p.add_argument("--path", "-p", action="store", type=str, help="List/search custom path", default='')
|
||||
p.add_argument("--exact", "-e", action="store_true", help="Match exact search term")
|
||||
p.add_argument("--cache", action="store_true", help="Cache index search (useful with deep directory trees)")
|
||||
p.add_argument("--context_filter", "-c", action="store", type=str, help="Filter context", choices=['context', 'project', 'tag'], default=None)
|
||||
p.add_argument("command", nargs="?", default=None, metavar='Command',
|
||||
help=command_help, type=str,
|
||||
choices=[
|
||||
'add', 'a',
|
||||
'remove', 'rem', 'r',
|
||||
'list', 'ls', 'dir', 'l',
|
||||
'copy', 'cp',
|
||||
'move', 'mv',
|
||||
'del', 'rm',
|
||||
'clear', 'c',
|
||||
'listproj', 'lsprj',
|
||||
'listcon', 'lsc',
|
||||
'listtag', 'lst',
|
||||
'clean', 'purge',
|
||||
'read'
|
||||
])
|
||||
p.add_argument("file", nargs="?", type=str, help=SUPPRESS)
|
||||
p.add_argument("context", nargs="*", type=str, help=SUPPRESS)
|
||||
p.print_usage = p.print_help
|
||||
args = p.parse_args()
|
||||
|
||||
orvani = OrvaniTag()
|
||||
|
||||
if args.command in ['add', 'a']:
|
||||
if args.file and args.context:
|
||||
orvani.add(args.file, *args.context)
|
||||
|
||||
elif args.command in ['remove', 'rem', 'r']:
|
||||
if args.file and args.context:
|
||||
orvani.remove(args.file, *args.context)
|
||||
|
||||
elif args.command in ['list', 'ls', 'dir', 'l', 'listproj', 'lsprj', 'lp', 'listcon', 'lsc', 'lc', 'listtag', 'lst', 'lt']:
|
||||
query = [args.file] + args.context
|
||||
if args.command in ['listproj', 'lsprj', 'lp'] or args.context_filter == 'project':
|
||||
args.context_filter = 'projects'
|
||||
if args.command in ['listcon', 'lsc', 'lc'] or args.context_filter == 'context':
|
||||
args.context_filter = 'contexts'
|
||||
if args.command in ['listtag', 'lst', 'lt'] or args.context_filter == 'tag':
|
||||
args.context_filter = 'tags'
|
||||
if query:
|
||||
r = orvani.list(args.path, args.context_filter, args.exact, args.not_recursive, args.cache, *query)
|
||||
mktable(' '.join(sys.argv[1:]), r)
|
||||
|
||||
elif args.command in ['copy', 'cp']:
|
||||
if args.file and args.context:
|
||||
orvani.move(args.file, args.context[0], True, args.no_file_operation)
|
||||
|
||||
elif args.command in ['move', 'mv']:
|
||||
if args.file and args.context:
|
||||
orvani.move(args.file, args.context[0], False, args.no_file_operation)
|
||||
|
||||
elif args.command in ['del', 'rm']:
|
||||
if args.file:
|
||||
orvani.delete(args.file, args.no_file_operation)
|
||||
|
||||
elif args.command in ['purge']:
|
||||
if not args.file:
|
||||
args.file = '.'
|
||||
target = Path(args.file)
|
||||
context_file = target / CONTEXT_FILE
|
||||
cache_file = target / CACHE_FILE
|
||||
context_file.unlink(missing_ok=True)
|
||||
cache_file.unlink(missing_ok=True)
|
||||
if args.not_recursive:
|
||||
for (root,dirs,files) in os.walk(args.file):
|
||||
if dirs:
|
||||
for dir in dirs:
|
||||
rpath = os.path.join(root, dir)
|
||||
Path(CONTEXT_FILE).unlink(missing_ok=True)
|
||||
Path(CACHE_FILE).unlink(missing_ok=True)
|
||||
|
||||
elif args.command in ['clean']:
|
||||
if not args.file:
|
||||
args.file = ''
|
||||
orvani.purge(args.file, args.not_recursive)
|
||||
|
||||
elif args.command in ['read']:
|
||||
orvani.read_meta()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
print(entry)
|
||||
10
test/.context.yaml
Normal file
10
test/.context.yaml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
files:
|
||||
test.txt:
|
||||
contexts:
|
||||
- test
|
||||
note: frrr
|
||||
projects:
|
||||
- test
|
||||
tags:
|
||||
- faa
|
||||
- test
|
||||
0
test/test.txt
Normal file
0
test/test.txt
Normal file
Loading…
Add table
Add a link
Reference in a new issue