Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build Datasette with PyInstaller and bundle it into an installable Electron app #7

Closed
simonw opened this issue Aug 24, 2021 · 12 comments
Labels
ci packaging Anything involving making stuff installable wontfix This will not be worked on

Comments

@simonw
Copy link
Owner

simonw commented Aug 24, 2021

No description provided.

@simonw simonw added the ci label Aug 24, 2021
@simonw
Copy link
Owner Author

simonw commented Aug 24, 2021

@simonw
Copy link
Owner Author

simonw commented Aug 24, 2021

Once PyInstaller has built a datasette binary I need to bundle that in the Electron app - here's a tutorial: https://ganeshrvel.medium.com/bundle-a-precompiled-binary-or-native-file-into-an-electron-app-beacc44322a9

@simonw
Copy link
Owner Author

simonw commented Aug 24, 2021

I figured out how to build Datasette using PyInstaller here: simonw/datasette#93 (comment)

@simonw
Copy link
Owner Author

simonw commented Aug 24, 2021

Also useful: I mostly figured out how to sign the Datasette executable in simonw/datasette#1171

@simonw
Copy link
Owner Author

simonw commented Aug 30, 2021

Needs to bundle the new datasette-app-support plugin that now lives in this repo as of #15.

@simonw
Copy link
Owner Author

simonw commented Aug 30, 2021

Bundling the Datasette binary looks a little complicated, this is the best answer I have found so far: https://stackoverflow.com/questions/33152533/bundling-precompiled-binary-into-electron-app

@simonw
Copy link
Owner Author

simonw commented Aug 30, 2021

@simonw
Copy link
Owner Author

simonw commented Aug 30, 2021

Another option worth considering, if I can't get electron-builder or electron-packager to work, is to assemble the Datasette.app package manually:

https://www.electronjs.org/docs/tutorial/application-distribution

This involves using a precompiled version of Electron and dropping the necessary files into the right places. It may be easier to get the datasette binary included correctly this way.

@simonw
Copy link
Owner Author

simonw commented Aug 30, 2021

I'm going to break this into smaller tasks.

@zaSmilingIdiot
Copy link

zaSmilingIdiot commented Aug 30, 2021

I'm not sure what the exact issues experienced using PyInstaller are, but hoping this helps in some way:

Firstly, you'll need electron-builder and electron-notarize installed (via npm or yarn).
We're using package.json to provide the electron-builder configuration, so the details below is based on that (although you can specify config in a separate file and/or script your own).
The basic are as follows:
In package.json :
Our build script for packaging mac does some pre-building of our application, and then runs electron-builder -m.
The build config in package.json looks something like:

  "build": {
    ...
    "afterSign": "build/notarize.js",
    "directories": {
        ...
    },
    "files": [
        ...
    ],
    "mac": {
      ...
      "hardenedRuntime": true,
      "gatekeeperAssess": false,
      "entitlements": "build/mac/entitlements.mac.plist",
      "entitlementsInherit": "build/mac/entitlements.mac.plist",
      "target": [
        "zip",
        "dmg"
      ]
    },
    "dmg": {
      ...
      "sign": false,
    },

    "asar": true,
    "asarUnpack": [
        ...
    ]
  },

For signing and notarizing, it seems that the following needs to be set accordingly:
build.mac.hardenedRuntime: true
build.mac.gatekeeperAssess: false
build.dmg.sign: false

See the electron-builder for the rest of the config that can and/or should be set.

Next, build.afterSign refers to a script that does the notarization. It currently looks like this:

const nodePath = require('path');
const { notarize } = require('electron-notarize');
const packageConfig = require('../package.json');

require('dotenv').config({ path: nodePath.join(__dirname, 'mac', '.env') });

exports.default = async function notarizing(context) {
  const { electronPlatformName, appOutDir } = context;
  if (electronPlatformName !== 'darwin') {
    return;
  }

  const appName = context.packager.appInfo.productFilename;

  return await notarize({
    appBundleId: packageConfig.build.appId,
    appPath: `${appOutDir}/${appName}.app`,
    appleId: process.env.APPLEID,
    appleIdPassword: process.env.APPLEIDPASSWORD,
    ascProvider: process.env.APPLEASCPROVIDER
  });
};

Note that in the script, around the 5th line, dotenv is used to load environment variables from a file... this isn't absolutely really necessary but the process.env.* values used later in the above script should be set in some way or another (or otherwise you can hardcode them but probably don't do that... 😸 )

Finally, the build.mac.entitlements and build.mac.entitlementsInherit values should point to a .plist file. I think the minimum basic one looks as follows but should be edited to your requirements (there's a good couple example online):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>com.apple.security.cs.allow-jit</key>
    <true/>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>
    <key>com.apple.security.cs.disable-library-validation</key>
    <true/>
  </dict>
</plist>

Not sure if that helps in any way, but hopefully gets you somewhere...

@simonw
Copy link
Owner Author

simonw commented Aug 30, 2021

Thanks very much, that looks really useful!

@simonw
Copy link
Owner Author

simonw commented Aug 31, 2021

I'm going with an alternative approach described in #25 - I'll re-open this issue if I decide to switch back to using PyInstaller.

@simonw simonw closed this as completed Aug 31, 2021
@simonw simonw added the wontfix This will not be worked on label Aug 31, 2021
@simonw simonw removed this from the First public installer release milestone Aug 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ci packaging Anything involving making stuff installable wontfix This will not be worked on
Projects
None yet
Development

No branches or pull requests

2 participants