ronaldoussoren / py2app

py2app is a Python setuptools command which will allow you to make standalone Mac OS X application bundles and plugins from Python scripts.
Other
341 stars 36 forks source link

Framework inclusion "failed due to spurious EAGAIN" #126

Open ronaldoussoren opened 10 years ago

ronaldoussoren commented 10 years ago

Original report by fwenzel (Bitbucket: fwenzel, GitHub: fwenzel).


I have a pyobjc-based project called UpShot that I am currently adding automated updates to.

For that to work I need to include the Sparkle Framework. However, when I add framework=['frameworks/Sparkle.framework'] to settings, my py2app build step fails as follows:

[...]
copying file frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/info.nib -> /Users/fred/dev/upshot/dist/UpShot.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/info.nib
copying file frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib -> /Users/fred/dev/upshot/dist/UpShot.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib
creating /Users/fred/dev/upshot/dist/UpShot.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib
copying file frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/classes.nib -> /Users/fred/dev/upshot/dist/UpShot.app/Contents/Frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/classes.nib
copying file frameworks/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/classes.nib failed due to spurious EAGAIN, retrying in 2 seconds
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr

The file where it fails is not always the same. Sometimes it's in en.lproj, sometimes in es.lproj, and sometimes in de.lproj.

Any idea why this happens? I am also surprised how it says it is going to retry and then instead it crashes.

Any hint where I could look to find out what is happening is appreciated. I poked around the py2app source code for a bit but did not find any obvious reason why this would happen.

ronaldoussoren commented 10 years ago

Original comment by fwenzel (Bitbucket: fwenzel, GitHub: fwenzel).


This is where it happens, though not why: https://bitbucket.org/ronaldoussoren/py2app/src/3e50b18722c57735988e13cfaacd59b163fda654/py2app/util.py?at=default#cl-144

ronaldoussoren commented 10 years ago

Original comment by fwenzel (Bitbucket: fwenzel, GitHub: fwenzel).


Fun fact, I changed the order of the two lines:

time.sleep(2)
log.info("copying file %s failed due to spurious EAGAIN, retrying in 2 seconds", source)

and now it works. Apparently, writing to stderr before the "cleanup" has happened, this will break. Is _copy_file using threads somewhere?

ronaldoussoren commented 10 years ago

Original comment by fwenzel (Bitbucket: fwenzel, GitHub: fwenzel).


For now I'll monkeypatch this workaround/fix into my app:

# XXX Workaround for #126/
# zipio throws IOError and needs time for cleanup. Lolwut?
import py2app
if py2app.__version__ == '0.7.3':
    import time
    import py2app.util
    def copy_decorator(f):
        def decorated(*args, **kwargs):
            try:
                f(*args, **kwargs)
            except:
                time.sleep(2)
                raise
        return decorated
    py2app.util._copy_file = copy_decorator(py2app.util._copy_file)

... though I'd rather land this upstream. Do you want a pull request?

ronaldoussoren commented 10 years ago

Original comment by Ronald Oussoren (Bitbucket: ronaldoussoren, GitHub: ronaldoussoren).


This is a very strange problem, and is probably related to the equally mysterious issue that led to the retry loop in the first place.

I'd love a pull request for switching the order of the sleep() and info() calls if that fixes the problem for you.

To answer an earlier question: py2app does not use threads and I don't understand yet what causes these problem. Py2app does use subprocesses (through subprocess.Popen) to run command-line tools when your program includes nib files or core data models, but that shouldn't cause this problem.

ronaldoussoren commented 10 years ago

Original comment by Hannu Valtonen (Bitbucket: Ormod, GitHub: Ormod).


I hit the same issue, I just commented out the log.info that's mentioned above and everything started working again just fine.