from docopt import docopt
from farmfs import getvol
from farmfs import reverse
from farmfs.util import empty2dot
from func_prototypes import constructors
from os import getcwdu
from fs import Path

def printNotNone(value):
  if value is not None:
    print value

def print_file(path, type_):
  if type_ == "link":
    print type_, path, path.readlink()
  else:
    print type_, path

def walk(foo, parents, exclude, match):
  for parent in parents:
    for (path, type_) in parent.entries(exclude):
      if type_ in match:
        foo(path, type_)

USAGE = \
"""
FarmDBG

Usage:
  farmdbg findvol
  farmdbg reverse <link>
  farmdbg key read <key>
  farmdbg key write <key> <value>
  farmdbg key delete <key>
  farmdbg key list [<key>]
  farmdbg walk (keys|userdata|root)
  farmdbg checksum <path>...
  farmdbg fix link <file> <target>
  farmdbg rewrite-links <udd> <target>
"""

def main():
  args = docopt(USAGE)
  cwd = Path(getcwdu())
  vol = getvol(cwd)
  if args['findvol']:
    print "Volume found at: %s" % vol.root
  elif args['reverse']:
    path = Path(args['<link>'], cwd)
    for p in reverse(vol, path):
      print p
  elif args['key']:
    db = vol.keydb
    key = args['<key>']
    if args['read']:
      printNotNone(db.readraw(key))
    elif args['delete']:
      db.delete(key)
    elif args['list']:
      for v in db.list(key):
        print v
    elif args['write']:
      value = args['<value>']
      db.write(key, value)
  elif args['walk']:
    if args['root']:
      walk(print_file, [vol.root], [str(vol.mdd)], ["file", "dir", "link"])
    elif args['userdata']:
      walk(print_file, [vol.udd], [str(vol.mdd)], ["file"])
    elif args['keys']:
      print "\n".join(vol.keydb.list())
  elif args['checksum']:
    paths = map(lambda x: Path(x, cwd), empty2dot(args['<path>']))
    for p in paths:
      print p.checksum(), p
  elif args['link']:
    f = Path(args['<file>'], cwd)
    t = Path(args['<target>'], cwd)
    if not f.islink():
      raise ValueError("%s is not a link. Refusing to fix" % (f))
    f.unlink()
    f.symlink(t)
  elif args['rewrite-links']:
    udd = Path(args['<udd>'], cwd)
    target = Path(args['<target>'], cwd)
    walk(print_file, [target], [str(udd)], ["link"])



@@ -189,16 +189,56 @@
 ort Path
+%0Afrom functools import partial%0Aimport re
 %0A%0Adef pr
@@ -418,16 +418,686 @@
 , path%0A%0A
+def reverser(num_segs):%0A  r = re.compile(%22((%5C/(%5B0-9%5D%7C%5Ba-f%5D)+)%7B%25d%7D)$%22 %25 (num_segs+1))%0A  def checksum_from_link(link):%0A    m = r.search(str(link))%0A    if (m):%0A      csum = m.group()%0A      return csum%5B1:%5D%0A    else:%0A      raise ValueError(%22link %25s checksum didn't parse%22 %25(link))%0A  return checksum_from_link%0A    %0Adefault_reverser = reverser(3)%0A%0Adef repair_link(udd, path, type_):%0A  assert(type_ == %22link%22)%0A  old = path.readlink()%0A  csum = default_reverser(old)%0A  new = Path(csum, udd)%0A  if not new.isfile():%0A    raise ValueError(%22%25d is missing, cannot relink%22 %25 new)%0A  else:%0A    print %22Relinking %25s from %25s to %25s%22 %25 (path, old, new)%0A    path.unlink()%0A    path.symlink(new)%0A%0A
 def walk
@@ -2881,31 +2881,64 @@
 wd)%0A    
-walk(print_file
+fixer = partial(repair_link, udd)%0A    walk(fixer
 , %5Btarge

add link repair tool