Skip to content

Commit

Permalink
Update Alfred-Workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
deanishe committed Aug 15, 2015
1 parent bb23cae commit 0eda4b3
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 20 deletions.
Binary file not shown.
2 changes: 1 addition & 1 deletion src/version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.2.1
1.2.2
2 changes: 1 addition & 1 deletion src/workflow/version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.12
1.13
2 changes: 0 additions & 2 deletions src/workflow/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
import urlparse
import zlib

import sys


USER_AGENT = u'Alfred-Workflow/1.11 (http://www.deanishe.net)'

Expand Down
102 changes: 86 additions & 16 deletions src/workflow/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,25 @@
"""

from __future__ import print_function, unicode_literals
from contextlib import contextmanager

import binascii
import os
import sys
import string
import re
import plistlib
import subprocess
import unicodedata
import shutil
import json
from contextlib import contextmanager
import cPickle
import pickle
import time
import errno
import json
import logging
import logging.handlers
import os
import pickle
import plistlib
import re
import shutil
import signal
import string
import subprocess
import sys
import time
import unicodedata

try:
import xml.etree.cElementTree as ET
Expand Down Expand Up @@ -436,9 +437,13 @@


####################################################################
# Keychain access errors
# Lockfile and Keychain access errors
####################################################################

class AcquisitionError(Exception):
"""Raised if a lock cannot be acquired."""


class KeychainError(Exception):
"""Raised by methods :meth:`Workflow.save_password`,
:meth:`Workflow.get_password` and :meth:`Workflow.delete_password`
Expand Down Expand Up @@ -790,6 +795,69 @@ def elem(self):
return root


class LockFile(object):
"""Context manager to create lock files"""

def __init__(self, protected_path, timeout=0, delay=0.05):
self.lockfile = protected_path + '.lock'
self.timeout = timeout
self.delay = delay
self._locked = False

@property
def locked(self):
"""`True` if file is locked by this instance."""
return self._locked

def acquire(self, blocking=True):
"""Acquire the lock if possible.
If the lock is in use and ``blocking`` is ``False``, return
``False``.
Otherwise, check every `self.delay` seconds until it acquires
lock or exceeds `self.timeout` and raises an exception.
"""
start = time.time()
while True:
try:
fd = os.open(self.lockfile, os.O_CREAT | os.O_EXCL | os.O_RDWR)
with os.fdopen(fd, 'w') as fd:
fd.write('{0}'.format(os.getpid()))
break
except OSError as err:
if err.errno != errno.EEXIST: # pragma: no cover
raise
if self.timeout and (time.time() - start) >= self.timeout:
raise AcquisitionError('Lock acquisition timed out.')
if not blocking:
return False
time.sleep(self.delay)

self._locked = True
return True

def release(self):
"""Release the lock by deleting `self.lockfile`."""
self._locked = False
os.unlink(self.lockfile)

def __enter__(self):
"""Acquire lock."""
self.acquire()
return self

def __exit__(self, typ, value, traceback):
"""Release lock."""
self.release()

def __del__(self):
"""Clear up `self.lockfile`."""
if self._locked: # pragma: no cover
self.release()


@contextmanager
def atomic_writer(file_path, mode):
"""Atomic file writer.
Expand Down Expand Up @@ -851,6 +919,7 @@ def signal_handler(self, signum, frame):
self._caught_signal = (signum, frame)

def __call__(self, *args, **kwargs):
self._caught_signal = None
# Register handler for SIGTERM, then call `self.func`
self.old_signal_handler = signal.getsignal(signal.SIGTERM)
signal.signal(signal.SIGTERM, self.signal_handler)
Expand Down Expand Up @@ -924,9 +993,10 @@ def save(self):
data = {}
for key, value in self.items():
data[key] = value
with atomic_writer(self._filepath, 'wb') as file_obj:
json.dump(data, file_obj, sort_keys=True, indent=2,
encoding='utf-8')
with LockFile(self._filepath):
with atomic_writer(self._filepath, 'wb') as file_obj:
json.dump(data, file_obj, sort_keys=True, indent=2,
encoding='utf-8')

# dict methods
def __setitem__(self, key, value):
Expand Down

0 comments on commit 0eda4b3

Please sign in to comment.