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

Add support for prebuilt asars #823

Merged
merged 2 commits into from Oct 25, 2018
Merged

Add support for prebuilt asars #823

merged 2 commits into from Oct 25, 2018

Conversation

jsg2021
Copy link
Contributor

@jsg2021 jsg2021 commented Apr 10, 2018

  • I have read the contribution documentation for this project.
  • I agree to follow the code of conduct that this project follows, as appropriate.
  • The changes are appropriately documented (if applicable).
  • The changes have sufficient test coverage (if applicable).
  • The testsuite passes successfully on my local machine (if applicable).

Summarize your changes:
I implemented the --asar.filename option referenced in #161

@welcome
Copy link

welcome bot commented Apr 10, 2018

Thanks for opening a pull request!

Here are some highlighted action items that will help get it across the finish line, from the
pull request guidelines:

  • Follow the JavaScript coding style.
  • Run npm run lint locally to catch formatting errors earlier.
  • Document any user-facing changes in NEWS.md and other docs.
  • Include tests when adding/changing behavior.

Development and triage is community-driven, so please be patient and we will get back to you as soon as we can.

@malept malept self-requested a review April 10, 2018 18:34
@malept malept changed the title Implement #161 adds --asar.filename support Add support for asar.filename Apr 10, 2018
@codecov
Copy link

codecov bot commented Apr 10, 2018

Codecov Report

Merging #823 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@          Coverage Diff          @@
##           master   #823   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files          12     12           
  Lines         622    643   +21     
=====================================
+ Hits          622    643   +21
Impacted Files Coverage Δ
ignore.js 100% <100%> (ø) ⬆️
platform.js 100% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a5e0f62...2183e42. Read the comment docs.

Copy link
Member

@malept malept left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the pull request! This is an excellent starting point. I've made several comments that should hopefully move this PR in the right direction. Let me know if there's anything I need to clarify.

.editorconfig Outdated

[package.json]
indent_style = space
indent_size = 2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're going to add this, it should be in a separate PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry about that, I didn't mean to add that. I was trying to follow the current style and that file made my editor honor it.

NEWS.md Outdated
@@ -4,6 +4,8 @@

[Unreleased]: https://github.com/electron-userland/electron-packager/compare/v12.0.0...master

* Added `asar.filename` to support pre-built asar files.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please adjust this to conform to the Keep a Changelog format?

docs/api.md Outdated
- `ordering` (*String*): A path to an ordering file for packing files. An explanation can be found on the [Atom issue tracker](https://github.com/atom/atom/issues/10163).
- `unpack` (*String*): A [glob expression](https://github.com/isaacs/minimatch#features), when specified, unpacks the file with matching names to the `app.asar.unpacked` directory.
- `unpackDir` (*String*): Unpacks the dir to the `app.asar.unpacked` directory whose names exactly or pattern match this string. The `asar.unpackDir` is relative to `dir`.

Some examples:

- `asar.filename = './dist/app.asar'` will short-circuit creating the asar, and just copy that one into the electron bundle.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there needs to be an example for this, it should be self-explanatory.

docs/api.md Outdated
@@ -183,12 +183,14 @@ is not restricted to the official set if [`download.mirror`](#download) is set.
*Boolean* or *Object* (default: `false`)

Whether to package the application's source code into an archive, using [Electron's archive format](https://github.com/electron/asar). Reasons why you may want to enable this feature are described in [an application packaging tutorial in Electron's documentation](http://electron.atom.io/docs/v0.36.0/tutorial/application-packaging/). When the value is `true`, pass default configuration to the `asar` module. The configuration values listed below can be customized when the value is an `Object`. Supported parameters include, but are not limited to:
- `filename` (*String*): circumvents the asar generation and lets you specify your own pre-built asar file/directory.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description should start with "A path to", like ordering below it.

test/_setup.js Outdated
@@ -67,13 +67,14 @@ function npmInstallForFixture (fixture) {
return true
} else {
console.log(`Running npm install in fixtures/${fixture}...`)
return exec('npm install --no-bin-links', {cwd: fixtureDir})
return exec('npm install --no-bin-links --no-package-lock', {cwd: fixtureDir})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in a different PR.

{
"name": "PrebuiltAsar",
"version": "0.0.1",
"description": "A test of the renamed from `electron-prebuilt` to `electron`",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description needs to be updated.

platform.js Outdated
@@ -154,6 +154,19 @@ class App {

const dest = path.join(this.originalResourcesDir, 'app.asar')
debug(`Running asar with the options ${JSON.stringify(asarOptions)}`)

if (asarOptions.filename) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that if there are other asarOptions other than filename and filename is set, it should warn that the other options won't be used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should that happen here? or in the argument parsing?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should happen here. If it happens in argument parsing, people who use the JS API (such as users of Electron Forge or ember-electron) will not get the warning.

platform.js Outdated
debug(`Copying asar: ${src} to ${target}`)
return fs.copy(src, target, {overwrite: false, errorOnExist: true})
})
.then(() => fs.remove(this.originalResourcesAppDir))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for efficiency purposes, if asar.filename is set, we shouldn't even copy the app directory in the first place. Then we can get rid of this fs.remove call.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started to go down that route, but tried to keep the change minimal. I'll short circuit that.

platform.js Outdated

return fs.stat(src)
.then(stat => {
const target = stat.isFile() ? dest : this.originalResourcesDir
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain how target is determined? Shouldn't target always be dest?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the user specified a directory (containing their app.asar and additional resources) fs-extra's copy requires the dest to be a directory... if the src is a file, it requires dest to be a file.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear from the docs that you can specify a directory for asar.filename. Although even if it did, I would disagree with it because the name of the option makes that choice not obvious. I think the value of asar.filename should only be an ASAR file.

"main": "main.js",
"devDependencies": {
"electron": "^1.8.0",
"electron-prebuilt": "^1.4.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should only be one item in devDependencies, and it should be "electron": "1.3.1". Every time we add a new Electron version to the tests, it takes longer to run the tests due to downloading prebuilt binaries.

NEWS.md Outdated
@@ -4,6 +4,10 @@

[Unreleased]: https://github.com/electron-userland/electron-packager/compare/v12.0.0...master

### Added

* `asar.filename` to support pre-built asar files.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit, remove the period and add (#823) at the end.

docs/api.md Outdated
@@ -183,6 +183,7 @@ is not restricted to the official set if [`download.mirror`](#download) is set.
*Boolean* or *Object* (default: `false`)

Whether to package the application's source code into an archive, using [Electron's archive format](https://github.com/electron/asar). Reasons why you may want to enable this feature are described in [an application packaging tutorial in Electron's documentation](http://electron.atom.io/docs/v0.36.0/tutorial/application-packaging/). When the value is `true`, pass default configuration to the `asar` module. The configuration values listed below can be customized when the value is an `Object`. Supported parameters include, but are not limited to:
- `filename` (*String*): A path to a pre-built asar file. This will circumvent the asar generation and lets you specify your own pre-built asar file.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kind of redundant. Let me think about a better way to word this.

platform.js Outdated
return true
}
})
const asarOptions = common.createAsarOpts(this.opts) || {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point asarOptions should be an instance variable, no need to calculate it twice.

: fs.copy(this.opts.dir, this.originalResourcesAppDir, {
filter: ignore.userIgnoreFilter(this.opts),
dereference: this.opts.derefSymlinks
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather have a real if statement than a multi-line ternary statement.

} else {
return true
}
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know whether afterPrune and afterCopy hooks should be run, since neither of those operations actually took place, and this.originalResourcesAppDir doesn't actually exist.

Copy link
Contributor Author

@jsg2021 jsg2021 Apr 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I didn't know what those hooks were for... I've changed it to just return early.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think returning early is the right solution... we may have to adjust the hook signature so that it's either the path to the resources app directory, or the path to the app.asar file (which would be a breaking change).

@MarshallOfSound since you have dealt with a lot of code relating to the hooks, you might have some insight here.

test/asar.js Outdated
return fs.pathExists(path.join(resourcesPath, 'app'))
}).then(exists => {
return t.false(exists, 'app subdirectory should NOT exist when app.asar is built')
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be:

      }).then(exists => t.false(exists, 'app subdirectory should NOT exist when app.asar is built'))

const src = path.resolve(this.asarOptions.filename)
if (Object.keys(this.asarOptions).length > 1) {
common.warning('asar.filename has been specified, all other asar options will be ignored')
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have a test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you mean? Test that it warns? or test that the other options are ignored? If the later, how should that be done?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test that it warns. This is an example of doing that (although it should probably be genericized into a function):

https://github.com/electron-userland/electron-packager/blob/a7437b908e68e97b288173759d0538efe7798c82/test/mas.js#L18-L33

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

Copy link
Member

@malept malept left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll need to take another pass at the diff later tonight, but one thing I noticed is that it should also be documented in usage.txt (which I should replace with yargs declarations...).

@malept
Copy link
Member

malept commented Apr 10, 2018

I'm also a little worried about the drop in code coverage, but let's see what it looks like after the latest changes go through CI.

@jsg2021
Copy link
Contributor Author

jsg2021 commented Apr 10, 2018

I updated the usage.txt.

platform.js Outdated
return fs.stat(src)
.then(stat => {
if (!stat.isFile()) {
throw new Error(`${src} must be an asar file.`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member

@malept malept left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside from the suggestions below, the one thing holding back this PR is how to deal with the hooks. I'm pretty sure that omitting the hooks when asar.filename is set will break Electron Forge, but I don't know exactly what the correct way to resolve that is.

docs/api.md Outdated
@@ -183,6 +183,7 @@ is not restricted to the official set if [`download.mirror`](#download) is set.
*Boolean* or *Object* (default: `false`)

Whether to package the application's source code into an archive, using [Electron's archive format](https://github.com/electron/asar). Reasons why you may want to enable this feature are described in [an application packaging tutorial in Electron's documentation](http://electron.atom.io/docs/v0.36.0/tutorial/application-packaging/). When the value is `true`, pass default configuration to the `asar` module. The configuration values listed below can be customized when the value is an `Object`. Supported parameters include, but are not limited to:
- `filename` (*String*): A path to a pre-built asar file. (This will circumvent the asar generation)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A path to a pre-built asar file (this will circumvent asar generation).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

test/asar.js Outdated
sinon.spy(console, 'warn')
return util.packageAndEnsureResourcesPath(t, opts)
.then(generatedResourcesPath => {
console.warn.calledWithExactly('WARNING: asar.filename has been specified, all other asar options will be ignored')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be wrapped in t.true()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, i’ve been in jest land for a while, i assumed sinon made the assertion. i’ll update.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

usage.txt Outdated
@@ -25,6 +25,7 @@ asar whether to package the source code within your app into an ar
--asar and its sub-properties simultaneously.

Properties supported:
- filename: path to a pre-built asar file. (This will circumvent the asar generation)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

path to a pre-built asar file (this will circumvent asar generation)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@jsg2021
Copy link
Contributor Author

jsg2021 commented Apr 11, 2018

None of this is breaking existing configurations. Without adding the asar.filename option, nothing changes.

The whole point of this option is to take control of the app bundle generation... the hooks can be external to this once the filename is used... if something is needed to be done to the app package, a more general hook can be added?

@jsg2021
Copy link
Contributor Author

jsg2021 commented Apr 11, 2018

the after prune hook still needs to be called since its unrelated to copy.

Never mind, I think I understand those hooks now. With a pre-built asar, you don't need the afterCopy/Prune hooks... all processing has already happened when the asar was generated outside of this tool. I can't think of anything you would need to hook for when specifying your own asar... so I'm sticking with my last comment. Just add a new pre-finalize hook called near the end before signing to allow last minute changes...

@MarshallOfSound
Copy link
Member

RE the hooks issue I believe the operation should throw an error if afterCopy or afterPune hooks are provided and a prebuilt ASAR file is provided , these are incompatible options.

Also I don't think this option should go into the options.asar option. That object is typically sent pretty much through to the ASAR module. This goes nowhere near the ASAR module, I'd prefer this if it was something like options.prebuiltAsar. This should also throw errors if that option is used in conjunction with any other ASAR option.

Also @malept we should just make forge error out instantly if this option is used 😄

@malept
Copy link
Member

malept commented Apr 11, 2018

The docs should be updated to note the asar, afterCopy, and afterPrune incompatibilities.

@jsg2021
Copy link
Contributor Author

jsg2021 commented Apr 11, 2018

I think I got all the suggestions implemented.

Copy link
Member

@malept malept left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it would be cleaner to deal with prebuiltAsar this way:

initialize () {
    debug(`Initializing app in ${this.stagingPath} from ${this.templatePath} template`)

    return fs.move(this.templatePath, this.stagingPath, { clobber: true })
      .then(() => {
        if (this.opts.prebuiltAsar) {
          return this.copyPrebuiltAsar()
            .then(() => this.removeDefaultApp())
        } else {
          return this.copyTemplate()
            .then(() => this.removeDefaultApp())
            .then(() => this.asarApp())
        }
      })
}

common.js Outdated
warning('--prebuiltAsar and --asar options are incompatible. Ignoring --asar')
delete args.asar
}
console.log('\n\n%s\n\n', JSON.stringify(args, null, 2))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✂️ debug line

common.js Outdated
warning('--prebuiltAsar and --ignore are incompatible. Ignoring --ignore')
}

if (!args['deref-symlinks']) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be !args.derefSymlinks

common.js Outdated
warning('--prebuiltAsar and --no-deref-symlinks are incompatible. Ignoring --no-deref-symlinks')
}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be outside of the CLI argument parsing, as I mentioned yesterday, because it will not give warnings to consumers of the JavaScript API.

docs/api.md Outdated
@@ -67,6 +67,10 @@ packager({
})
```

**NOTE:** `afterCopy` will not be called if `prebuiltAsar` is set.

---
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lines are unnecessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it was a nice visual grouping. I'll drop them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we're going to do that, it should be in a separate PR.

docs/api.md Outdated

A path to a pre-built asar file.

**NOTE:** This option circumvents many options such as `asar`, `afterCopy`, `afterPrune`, `ignore`, `prune`, or any option related to the copy processes. These options are for generating an app directory/asar with this tool. However, if a prebuilt asar file is provided, these options are not needed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd get rid of , or any option related to the copy processes. Also, it's a little too verbose in general, but I need some time to think of a better way to word it.

platform.js Outdated
if ((this.asarOptions || {}).filename) {
if (this.opts.prebuiltAsar) {
if (this.opts.afterCopy) {
return Promise.reject(new Error('afterCopy is incompatible with prebuiltAsar'))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should just be able to throw new Error.

Copy link
Contributor Author

@jsg2021 jsg2021 Apr 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't an async function, I was trying to make as little of a splash as possible. I hadn't looked to see if the callers were setup to handle thrown exceptions and not just promise rejections. I'll make it throw instead.

@jsg2021
Copy link
Contributor Author

jsg2021 commented Apr 11, 2018

I've updated to use your suggested initialize()

@jsg2021
Copy link
Contributor Author

jsg2021 commented Apr 11, 2018

looks like a transient error caused the signing test to fail for one of the jobs... but the rest seem to be passing. I haven't looked further into it, since its outside the scope of my changes and it has been passing.

@jsg2021
Copy link
Contributor Author

jsg2021 commented Apr 20, 2018

Anything I should change?

@jsg2021
Copy link
Contributor Author

jsg2021 commented Apr 25, 2018

@malept Would you like anything else? or do you think this is good?

@malept malept changed the title Add support for asar.filename Add support for prebuilt asars May 3, 2018
@jsg2021
Copy link
Contributor Author

jsg2021 commented May 3, 2018

I rebased from your current master

NEWS.md Outdated
@@ -24,6 +24,10 @@

* Upgraded `galactus` to `^0.2.1` to fix a bug with relative paths

### Added
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now in the wrong place

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, should be fixed now

@jsg2021
Copy link
Contributor Author

jsg2021 commented May 11, 2018

I hope all is well? Is this still wanted?

@jsg2021
Copy link
Contributor Author

jsg2021 commented May 16, 2018

I rebased again, let me know if any docs need touch ups.

@jsg2021
Copy link
Contributor Author

jsg2021 commented May 19, 2018

@malpet is there reservations for merging this?

@jsg2021
Copy link
Contributor Author

jsg2021 commented May 29, 2018

Your cleanup looks way better than my changes. :) I didn't want to change too much without fully comprehending the codebase. Sorry if I misunderstood your requests. Hope this gets merged 👍

@jsg2021
Copy link
Contributor Author

jsg2021 commented Jul 2, 2018

I've been using this branch to bundle my apps, the flag works well. Hope we can merge soon.

@jsg2021
Copy link
Contributor Author

jsg2021 commented Aug 4, 2018

Is this blocked by something? Anything I could help with?

@malept malept merged commit b487df2 into electron:master Oct 25, 2018
@welcome
Copy link

welcome bot commented Oct 25, 2018

Thanks for your contribution! 🎉

@jsg2021 jsg2021 deleted the asar-filename branch October 25, 2018 14:20
@jsg2021
Copy link
Contributor Author

jsg2021 commented Oct 25, 2018

🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants