kakaroto / SWProxy

Summoners War Data Extractor and Parser
GNU Lesser General Public License v3.0
164 stars 86 forks source link

Build a real Mac App #25

Open kakaroto opened 8 years ago

kakaroto commented 8 years ago

I see so many people completely lost on Mac, they don't even know how to change directory in a terminal. Having a single .app that they can double click and it opens for them (bundled with the dependencies) would be great. Would probably require the gui (issue #20) to be done first.

fperegrinvs commented 8 years ago

py2app and some tutorial

kakaroto commented 8 years ago

Yeah, I know how to do it (I maintain/build the Cura Lulzbot Edition which uses py2app), it just needs to be done! :) But without a GUI, it won't be very practical for users (not even sure you can have a mac app without a window of some sort).

ghost commented 8 years ago

I actually went down this path of the tutorial @lstern linked, heres the config I came up with


# -*- coding: utf-8 -*-
from setuptools import setup
import glob

# cant import the one from setup
def glob_plugins():
    ret = []
    for pattern in ('plugins/*.py', 'plugins/*.yapsy-plugin'):
        ret.extend(glob.glob(pattern))
    return ret

plugins = glob_plugins()

APP_NAME = 'SWParser'
APP = ['SWProxy.py']
DATA_FILES = []
OPTIONS = {
    'argv_emulation': True,
    # 'iconfile': 'app.icns',
    'plist': {
        'CFBundleName': APP_NAME,
        'CFBundleDisplayName': APP_NAME,
        'CFBundleGetInfoString': "Summoners War Data Parser",
        'CFBundleIdentifier': "com.sw.osx.swparser",
        'CFBundleVersion': "1.0",
        'CFBundleShortVersionString': "1.0",
        'NSHumanReadableCopyright': u"Copyright © 2016, Youness Alaoui"
    },
}

setup(
    app=APP,
    name=APP_NAME,
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)

I ended up with an application that seemed to be incomplete; it launched and did nothing

ghost commented 8 years ago

@kakaroto maybe you can take it that last bit; i think the APP list needs more files (but i got a weird error error: Multiple targets not currently supported) also DATA_FILES needs to relate to plugins somehow

stanleykylee commented 8 years ago

I used pyinstaller and had no problems creating a one file application. It will open up in terminal and works fine. Have you guys looked into that?

http://www.pyinstaller.org/

One thing to note, you'll need to include the import yapsy on the main SWProxy.py for pyinstaller to pick it up when it compiles the application.

EDIT: I've never used yapsy and pyinstaller doesn't work out of the box with the plug-ins. I'm going to have to play around with this again as I like the changes you guys have done but now pyinstaller doesn't work :(

stanleykylee commented 8 years ago

I got it to py2app to work with the following setup.py with one caveat - it doesn't load any gui and you don't see any messages anywhere so it looks like the application crashed. If you load console, you see the messages and the proxy works.

You can also see this if you run it directly in a terminal session:

./dist/SWProxy.app/Contents/MacOS/SWProxy

Not sure how to force the messages into a terminal session or if we really need a GUI to make this work.

# -*- coding: utf-8 -*-
from setuptools import setup
import glob

# cant import the one from setup
def glob_plugins():
    ret = []
    for pattern in ('plugins/*.py', 'plugins/*.yapsy-plugin'):
        ret.extend(glob.glob(pattern))
    return ret

plugins = glob_plugins()

APP_NAME = 'SWProxy'
APP = ['SWProxy.py']
DATA_FILES = [('plugins', plugins)]
OPTIONS = {
    'includes': ["Crypto.Cipher"],
    'argv_emulation': True,
    # 'iconfile': 'app.icns',
    'plist': {
        'CFBundleName': APP_NAME,
        'CFBundleDisplayName': APP_NAME,
        'CFBundleGetInfoString': "Summoners War Data Proxy",
        'CFBundleIdentifier': "com.sw.osx.swproxy",
        'CFBundleVersion': "1.0",
        'CFBundleShortVersionString': "1.0",
        'NSHumanReadableCopyright': u"Copyright © 2016, Youness Alaoui"
    },
}

setup(
    app=APP,
    name=APP_NAME,
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)
ghost commented 8 years ago

^^ might want to wrap code in the code brackets, the triple backtick

@stanleykylee http://www.pyinstaller.org/ if you got it working could you post instructions? either that or py2app im sure would work fine overall,

stanleykylee commented 8 years ago

@azrethos I got pyinstaller to work using the following .spec file. One issue though, because the data files (AUTHORS, plugin files) are uncompressed in a different location, I had to add a resource path wrapper to locate the files for it to work. Take a look at the SO site below and I can send a pull request later when I'm home from work if you guys agree with this.

pyinstaller --onefile with data files http://stackoverflow.com/questions/19669640/bundling-data-files-with-pyinstaller-2-1-and-meipass-error-onefile

SWProxy.spec

# -*- mode: python -*-

block_cipher = None

a = Analysis(['SWProxy.py'],
             pathex=['.'],
             binaries=None,
             datas=[ ('plugins/*.py', 'plugins'),
                     ('plugins/*.yapsy-plugin', 'plugins'),
                     ('AUTHORS', '.') ],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='SWProxy',
          debug=False,
          strip=False,
          upx=True,
          console=True )

pyinstaller command

pip install pyinstaller
pyinstaller SWProxy.spec

change to SWProxy.py

from SWPlugin import resource_path

def read_file_lines(fpath):
    try:
        # append resource path to filepath
        fpath = resource_path(fpath)
        with open(fpath, 'r') as fh:
            return map(lambda x:x.strip(), fh.readlines())
    except Exception:
        logger.debug('Failed to read file at {}'.format(fpath))
        return ''

change to SWPlugin.py

    def load_plugins(cls):
        manager = PluginManager()
        manager.setPluginPlaces([os.path.join(os.getcwd(), resource_path("plugins/"))])
        manager.collectPlugins()
        ret = manager.getAllPlugins()
        logger.info('Loaded {} plugins'.format(len(ret)))
        return ret

def resource_path(relative_path):
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative_path)

    return os.path.join(os.path.abspath("."), relative_path)
stanleykylee commented 8 years ago

Created a pull request with the changes.

stanleykylee commented 8 years ago

By the way, where should I document on how to use pyinstaller? Pyinstaller works for both Windows and OSX, so we should be able to create executables using the same .spec file. However, I can't test it as I don't have access to a Windows box at the moment.

kakaroto commented 8 years ago

I'll try it on windows. And docs could just go in the README file I guess. Anyways, the README needs to be rewritten as I think it's more confusing than anything else right now.

ghost commented 8 years ago

2nd readme re-do

kakaroto commented 8 years ago

Finally got around to testing it on Windows. It kept complaining about this :

2016-02-15 03:35:27,371: SWProxy - ERROR - Exception while executing plugin : global name 'SWPlugin' is not defined
Traceback (most recent call last):
  File "SWProxy.py", line 60, in onResponse
NameError: global name 'SWPlugin' is not defined

I don't know if it's because of your version in your repository that's buggy/missing some commits that fixes this, or if it's because the .exe is bad. Other thing to note is that a terminal window opens even though there's a GUI, so there needs to be an option to give pyinstaller to tell it that it's a windows app so it won't open a terminal.

stanleykylee commented 8 years ago

I believe it is your environment or the .exe? I pulled some strings and got a vanilla Windows VM spun up for me. Installed only Python 2.7, Microsoft Visual C++ Compiler for Python 2.7 (for pip) and Git. Then proceeded to:

pip install -r requirements.txt
pip install pyinstaller
pyinstaller SWProxy.spec

SWProxy.zip

I've attached the output .exe and let me know if it runs on your environment?

I'll have to look at how I can get the GUI to show up only without the terminal. I have never coded for GUI so I'll have to get back to you there.

stanleykylee commented 8 years ago

So last night I was pulling some rune data for a friend that was visiting and saw the same error you posed above (on my Mac) as well. I noticed that this only happens when using the GUI and not when using the --no-gui option. The same compiled executable worked when running with -g.

As I had mentioned, I'm not familiar with qt, have you noticed that the "global name 'SWPlugin' is not defined" only shows up when using GUI?

kakaroto commented 8 years ago

I hadn't tried without the GUI because the purpose is for people to use the GUI so I didn't think to try without. But you said you didn't have the issue yourself and I'm guessing you were testing it with the GUI, so why would it work sometimes and sometimes not. I don't really know what the problem is, it could be a simple "import SWPlugin" missing from a file somewhere and that's it, but I just don't have time to look for it unfortunately. Btw, for the console not appearing, here it is : https://pythonhosted.org/PyInstaller/#windows-and-mac-os-x-specific-options Just give '-w' option to pyinstaller when running it, and it will remove the console for both win and mac. (I havent' tested it though)

stanleykylee commented 8 years ago

Thanks for the additional info, I'll work on this today and see if I can come up with something shortly. I was never testing it with the GUI until recently. Without QT installed on my dev machine, it would always just error out on build and end up without launching the GUI. I should have been more specific about my environment.

stanleykylee commented 8 years ago

parents came into town unexpectedly, will look at this in a couple of days.

fperegrinvs commented 8 years ago

@stanleykylee just pinging you about this issue. I plan to release a new version today if we are able to proper pack the mac version

stanleykylee commented 8 years ago

@lstern when do you plan to release the new version? i've been swamped with work recently. I'll try to look at it today or tonight (i'm PST).

fperegrinvs commented 8 years ago

@stanleykylee I plan to release this as soon as I manage to have a working pack for mac. I merged your code to the gui branch and tried to make it run on a mac vm. I was unable to do so using pyinstaller but I suspect that there's some problem with my mac environment (and I did manage to run using python shell). The spec file worked like a charm on windows.

stanleykylee commented 8 years ago

@lstern great to hear it worked in Windows. I had to give up the VM. I'll pull the latest and try it again on my OS X.

laynem commented 8 years ago

@lstern If you need help testing on a mac im willing to help.

fperegrinvs commented 8 years ago

@stanleykylee if everything is ok, send me an zip file with the package so I can test on mine. @laynem nice! if @stanleykylee manage to package the app on mac, I'll let you know.

stanleykylee commented 8 years ago

I'll have to wait until I get home. For some reason the proxy stopped getting traffic through the VPN setup I have to connect back home.

fperegrinvs commented 8 years ago

How long until you get home ?

On Fri, Mar 4, 2016 at 7:49 PM, stanleykylee notifications@github.com wrote:

I'll have to wait until I get home. For some reason the proxy stopped getting traffic through the VPN setup I have to connect back home.

— Reply to this email directly or view it on GitHub https://github.com/kakaroto/SWProxy/issues/25#issuecomment-192506993.

stanleykylee commented 8 years ago

I'll be home from work in about 3 hours.

stanleykylee commented 8 years ago

SWProxy.zip

It compiled and I'm able to run it, but I can't actually test it since I don't have access to my home network from the game at the moment. If someone wants to try it on their OS X?

@lstern @laynem

fperegrinvs commented 8 years ago

@stanleykylee I just tried it. I was able to run and the proxy is working but plugins are being ignored and we still have a console window open (did you use the --windowed flag?). I tested the same version on windows and everything is working so it may be some small problem with the plugin path and pyinstaller flags.

stanleykylee commented 8 years ago

when the plugins are included as part of the package, it works fine. are you saying the windows version with pyinstaller works or are you using another freezer?

this is odd, when I ./SWProxy plugins show up. double clicking does not.

fperegrinvs commented 8 years ago

I'm using pyinstaller, latest version from gui branch where I reverted your plugin path change (the _MEIPASS trick). If its working in the package, maybe you are still using old code

stanleykylee commented 8 years ago

ignore my comment about part of the package. i'm using the latest code where you removed the path change. i'm trying to figure out why when i execute from console the plugins work fine but double clicking on it does not. are you seeing the same on your side?

fperegrinvs commented 8 years ago

seems that if we build without the console window, we can't use the -g flag