Advertisement
lpugoy

Insync Nemo plugin

Mar 8th, 2013
168
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.04 KB | None | 0 0
  1. print('loading insync nemo plugin..')
  2. from gi.repository import GObject
  3. from gi.repository import Nemo
  4.  
  5. DEV_MODE = False
  6.  
  7. import json
  8. import os
  9. import socket
  10. import sys
  11. import urllib
  12.  
  13.  
  14. FS_ENCODING = sys.getfilesystemencoding()   # C is 'ANSI_X3.4-1968'
  15.  
  16. def ipc_insync(**kw):
  17.   #print('<ipc-insync>',kw)
  18.   data = json.dumps( kw )
  19.   socket_file = u'/tmp/insync%r.sock' % os.getuid()
  20.   if not os.path.exists(socket_file):
  21.     if DEV_MODE:
  22.       print('WARN: insync socket not found')
  23.     return None
  24.   sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
  25.   try:
  26.     sock.connect(socket_file)
  27.   except:
  28.     return None
  29.   sock.send(data)
  30.   res = sock.recv(4096)
  31.   sock.close()
  32.   if res.strip():
  33.     return json.loads(res.strip())
  34.   else:
  35.     return None
  36.  
  37.  
  38. GDRIVE = ('Open in Google Drive', 'cm:open', 'web-browser-symbolic')
  39. SEPARATOR = (unicode(u'\u2015' * 10), None, None)
  40. SHARE =  ('Share', 'cm:share', 'send-to-symbolic')
  41. LINK =   ('Copy public Link', 'cm:public_link', 'document-save-symbolic')
  42.  
  43.  
  44. _EMBLEM_KEYS = {
  45.   'SYNCED': 'emblem-insync-synced',
  46.   'SYNCING': 'emblem-insync-syncing',
  47.   'ERROR': 'emblem-insync-error',
  48.   'DES_ERROR': 'emblem-insync-des-error',
  49.   'DES_SYNCING': 'emblem-insync-syncing',
  50. }
  51.  
  52.  
  53. class InsyncMenuProvider(GObject.GObject, Nemo.MenuProvider, Nemo.InfoProvider):
  54.  
  55.   DEFAULT_INSYNC_CONFIG_PATH = os.path.expanduser('~/.config/Insync')
  56.  
  57.   def __init__(self):
  58.     self._insync_active = False
  59.     self._insync_roots = None
  60.     self._symlinks = {}  # link : target
  61.  
  62.   def load_insync_settings(self):
  63.     msg = ipc_insync(command='GET-INFO')
  64.     if msg:
  65.       if DEV_MODE:
  66.         print('INSYNC ACTIVE')
  67.         print(msg)
  68.       self._insync_active = True
  69.       self._insync_roots = msg
  70.     else:
  71.       self._insync_active = False
  72.     symcache = os.path.join(self.DEFAULT_INSYNC_CONFIG_PATH, 'symlink-cache.json')
  73.     if os.path.isfile(symcache):
  74.       f = open(symcache, 'rb')
  75.       self._symlinks = json.load(f)
  76.       f.close()
  77.  
  78.   def get_background_items(self, window, file):
  79.     print( 'calling get background items' )
  80.     return None
  81.  
  82.   def get_file_items(self, window, files):
  83.     if DEV_MODE:
  84.       print('get file items', files)
  85.  
  86.     if len(files) != 1:
  87.       # TODO what can we do with mutiple files here
  88.       return None
  89.  
  90.     self.load_insync_settings()
  91.     if not self._insync_roots:
  92.       return None
  93.  
  94.     file = files[0]
  95.     path = urllib.unquote(file.get_uri()[len('file://'):])
  96.     path = unicode(path, FS_ENCODING)
  97.     if DEV_MODE:
  98.       print path
  99.     is_dir = os.path.isdir(path)
  100.  
  101.     roots = tuple([root + '/' for root in self._insync_roots])
  102.     if self._insync_active and path.startswith(roots):  ## this block requires insync daemon is running
  103.       tip = 'Insync folder actions' if is_dir else 'Insync file actions'
  104.       item = Nemo.MenuItem(
  105.         name="Insync",
  106.         label="Insync",
  107.         tip=tip,
  108.         icon='insync'
  109.       )
  110.       sub_menu = Nemo.Menu()
  111.       item.set_submenu(sub_menu)
  112.  
  113.       for text, cmd, icon in [GDRIVE, SEPARATOR, SHARE, LINK]:
  114.         menu_item = Nemo.MenuItem(name=text, label=text, tip=text, icon=icon)
  115.         if cmd:
  116.           menu_item.connect('activate', self.do_action, file, cmd)
  117.         else:
  118.           menu_item.sensitive = False
  119.         sub_menu.append_item(menu_item)
  120.  
  121.       return [item]
  122.     elif not path.startswith(tuple(self._insync_roots)):  ## do not allow paths starting with ~/Insync to be symlinked inside itself
  123.       targets = self._symlinks.values()
  124.       if DEV_MODE:
  125.         print 'self._symlinks', self._symlinks
  126.  
  127.       symlink_target = unicode(
  128.         urllib.unquote(file.get_uri()[len('file://'):]),
  129.         FS_ENCODING
  130.       )
  131.  
  132.       toplevel = self.make_symlinks_menu(symlink_target)
  133.       return [toplevel]
  134.  
  135.   def make_symlinks_menu(self, symlink_target):
  136.     uid = 0   # this is lame
  137.  
  138.     toplevel = Nemo.MenuItem(
  139.       name="Insync::%s" % uid,
  140.       label="Add to Insync",
  141.       tip="Add to Insync - creates a symlink to this folder, in the user folder you select",
  142.       icon='insync'
  143.     )
  144.     uid += 1
  145.  
  146.     submenu = Nemo.Menu()
  147.     toplevel.set_submenu(submenu)
  148.  
  149.     reverse_symlinks = dict((value, key) for key, value in self._symlinks.iteritems())
  150.     if symlink_target in reverse_symlinks:
  151.       full_path, symlink_name = os.path.split(reverse_symlinks[symlink_target])
  152.       _, folder_name = os.path.split(full_path)
  153.       label = u'%s/%s (linked)' % (folder_name, symlink_name)
  154.       item = Nemo.MenuItem(
  155.         name='Insync::%s' % uid,
  156.         label=label,
  157.         tip=label
  158.       )
  159.       submenu.append_item(item)
  160.       uid += 1
  161.     else:
  162.       _, target_name = os.path.split(symlink_target)
  163.  
  164.       for insync_root in self._insync_roots:
  165.         _, folder_name = os.path.split(insync_root)
  166.         if target_name in os.listdir(insync_root):
  167.           label = u'%s/%s (name in use)' % (folder_name, target_name)
  168.           item = Nemo.MenuItem(
  169.             name='Insync::%s' % uid,
  170.             label=label,
  171.             tip=label
  172.           )
  173.         else:
  174.           item = Nemo.MenuItem(
  175.             name='Insync::%s' % uid,
  176.             label=folder_name,
  177.             tip='create symlink in user root folder'
  178.           )
  179.           item.connect('activate', self.do_symlink, symlink_target, target_name, insync_root)
  180.  
  181.         submenu.append_item(item)
  182.         uid += 1
  183.  
  184.     return toplevel
  185.  
  186.   def do_symlink(self, menu, path, target, insync_root):
  187.     dest = os.path.join(insync_root, target)
  188.     if DEV_MODE:
  189.       print('<doing symlink>', path, dest)
  190.     self._symlinks[path] = dest
  191.     os.symlink(path, dest)
  192.     if not ipc_insync(command='IS-ALIVE') and os.path.isdir(self.DEFAULT_INSYNC_CONFIG_PATH):
  193.       symcache = os.path.join(self.DEFAULT_INSYNC_CONFIG_PATH, 'symlink-cache.json')
  194.       with open(symcache, 'wb') as f:
  195.         json.dump(self._symlinks, f)
  196.  
  197.   def do_action(self, menu, file, method):
  198.     path = urllib.unquote(
  199.       file.get_uri()[len('file://'):]
  200.     )
  201.     ipc_insync( method=method, full_path=path)
  202.  
  203.   def update_file_info_full(self, provider, handle, closure, file):
  204.     if file.get_uri_scheme() != 'file':
  205.       return
  206.  
  207.     filename = urllib.unquote(file.get_uri()[len('file://'):])
  208.     status = ipc_insync(command='GET-FILE-STATUS', full_path=filename)
  209.     if DEV_MODE:
  210.       print filename, status
  211.     if not status or status == 'UNKNOWN':
  212.       return Nemo.OperationResult.COMPLETE
  213.  
  214.     GObject.timeout_add(1, self.add_emblem, provider, handle, closure, file,
  215.                         filename, status)
  216.     return Nemo.OperationResult.IN_PROGRESS
  217.  
  218.  
  219.   def add_emblem(self, provider, handle, closure, file, filename, status):
  220.     emblem = _EMBLEM_KEYS[status]
  221.     if os.path.isdir(filename):
  222.       is_shared = ipc_insync(command='IS-FILE-SHARED', full_path=filename)
  223.       if is_shared:
  224.         emblem += '-shared'
  225.  
  226.     file.add_emblem(emblem)
  227.  
  228.     Nemo.info_provider_update_complete_invoke(closure, provider, handle,
  229.                                               Nemo.OperationResult.COMPLETE)
  230.     return False
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement