检测特定的Python.app实例是否已在运行

时间:2015-06-07 14:18:09

标签: python objective-c macos cocoa pyobjc

我正在尝试使用Python编写的OS X应用程序,并且需要检测是否已经存在使用某些脚本运行的Python.app实例。该脚本从CFBundleNamePython即时修改MyApp以更改菜单栏中的应用标题。

bundle = NSBundle.mainBundle()
info = bundle.localizedInfoDictionary() or bundle.infoDictionary()
info['CFBundleName'] = 'MyApp'

如果我启动另一个实例并检查正在运行的应用的CFBundleName,它只会告诉我原始值,即Python

for app in NSWorkspace.sharedWorkspace().runningApplications():
    bundle = NSBundle.bundleWithURL_(app.bundleURL())
    info = bundle.localizedInfoDictionary() or bundle.infoDictionary()
    name = info.get('CFBundleName')
    if name in ('Python', 'MyApp'):
        print name  # => prints Python

所以我需要找到一种方法来标记运行MyApp脚本的Python.app实例,以便能够中止启动重复实例。

有这样的方法吗?

更新

在有更好的解决方案之前,我将使用lockf

import fcntl
lockfile = open('/tmp/myapp.lock', 'w')
fcntl.lockf(lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)

更新2:

好吧,我仍然需要找到我关注的应用程序。目前,我只是循环遍历所有Python.app实例并逐个关注它们。通常,只有一个,但如果它们很少,它可能会很混乱。

from Foundation import NSWorkspace
from Cocoa import NSApplicationActivateAllWindows, NSApplicationActivateIgnoringOtherApps

try:
    import fcntl
    lockfile = open('/tmp/myapp.lock', 'w')
    fcntl.lockf(lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)

except IOError as e:
    assert (e.errno, e.strerror) == (35, 'Resource temporarily unavailable')

    for app in NSWorkspace.sharedWorkspace().runningApplications():
        if app.bundleIdentifier() == 'org.python.python':
            app.activateWithOptions_(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)
    exit()

更新3:

我将使用pid文件,直到出现更好的解决方案

LOCK_FILE = '/tmp/myapp.lock'
PID_FILE = '/tmp/myapp.pid'

try:
    import fcntl
    # NOTE: needs to be assigned to a variable for the lock to be preserved
    lockfile = open(LOCK_FILE, 'w')
    fcntl.lockf(lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)

except IOError as e:    
    try:
        with open(PID_FILE) as f:
            pid = int(f.read())
    except:
        pid = None

    for app in NSWorkspace.sharedWorkspace().runningApplications():
        if app.bundleIdentifier() == 'org.python.python':
            if not pid or pid == app.processIdentifier():
                app.activateWithOptions_(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)
    exit()

from Foundation import NSProcessInfo
info = NSProcessInfo.processInfo()
pid = info.processIdentifier()
with open(PID_FILE, 'w+') as f:
    f.write(str(pid))

2 个答案:

答案 0 :(得分:1)

有几种方法可以解决这个问题。其中:

  • libunique - 专为此设计的库
  • dbus - 内部通信系统

this post的答案中描述了其中许多内容。

给出了here的唯一实例的配方。

答案 1 :(得分:0)

一个不太精细的解决方案是使用命令行中没有killall的应用程序名称调用.app。这可以使用os.command()在您的Python脚本中完成。