Permalink
Browse files

refactor: remove js2asar.py and port logic to JS in more readable / G…

…N-style way (#16718)

* refactor: remove js2asar.py and port logic to JS in more readable / GN-style way

* refactor: further clean up ASAR impl, add new node_action GN template
  • Loading branch information...
MarshallOfSound committed Feb 5, 2019
1 parent 8582325 commit b202ad1e249d168875560b73375abca56b2ca3ab
Showing with 168 additions and 73 deletions.
  1. +45 −8 BUILD.gn
  2. +22 −12 build/asar.gni
  3. +21 −0 build/node.gni
  4. +14 −0 build/run-node.py
  5. +1 −1 default_app/index.html
  6. +1 −1 default_app/renderer.js
  7. +3 −0 filenames.gni
  8. +61 −0 script/gn-asar.js
  9. +0 −51 tools/js2asar.py
@@ -137,7 +137,12 @@ action("atom_js2c") {
rebase_path(sources, root_build_dir)
}

asar("js2asar") {
target_gen_electron_js = "$target_gen_dir/js/electron"
target_gen_default_app_js = "$target_gen_dir/js/default_app"

# TODO(MarshallOfSound)
# This copy will be replaced by a call to tsc in the future
copy("lib_js") {
sources = filenames.js_sources
if (enable_desktop_capturer) {
sources += [
@@ -156,18 +161,50 @@ asar("js2asar") {
"lib/browser/api/views/text-field.js",
]
}

outputs = [
"$target_gen_electron_js/{{source}}",
]
}

asar("electron_asar") {
deps = [
":lib_js",
]

root = "$target_gen_electron_js/electron/lib"
sources = get_target_outputs(":lib_js")
outputs = [
"$root_out_dir/resources/electron.asar",
]
root = "lib"
}

asar("app2asar") {
copy("default_app_js") {
sources = filenames.default_app_sources
outputs = [
"$target_gen_default_app_js/{{source}}",
]
}

copy("default_app_octicon_deps") {
sources = filenames.default_app_octicon_sources
outputs = [
"$target_gen_default_app_js/electron/default_app/octicon/{{source_file_part}}",
]
}

asar("default_app_asar") {
deps = [
":default_app_js",
":default_app_octicon_deps",
]

root = "$target_gen_default_app_js/electron/default_app"
sources = get_target_outputs(":default_app_js") +
get_target_outputs(":default_app_octicon_deps")
outputs = [
"$root_out_dir/resources/default_app.asar",
]
root = "default_app"
}

grit("resources") {
@@ -712,9 +749,9 @@ if (is_mac) {

bundle_data("electron_app_resources") {
public_deps = [
":app2asar",
":default_app_asar",
":electron_app_strings_bundle_data",
":js2asar",
":electron_asar",
]
sources = [
"$root_out_dir/resources/default_app.asar",
@@ -760,10 +797,10 @@ if (is_mac) {
sources = filenames.app_sources
include_dirs = [ "." ]
deps = [
":app2asar",
":default_app_asar",
":electron_app_manifest",
":electron_asar",
":electron_lib",
":js2asar",
":packed_resources",
"//content:sandbox_helper_win",
"//ui/strings",
@@ -1,5 +1,6 @@
import("npm.gni")
import("node.gni")

# TODO(MarshallOfSound): Move to electron/node, this is the only place it is used now
# Run an action with a given working directory. Behaves identically to the
# action() target type, with the exception that it changes directory before
# running the script.
@@ -32,19 +33,28 @@ template("chdir_action") {

template("asar") {
assert(defined(invoker.sources),
"Need sources in $target_name listing the JS files.")
"Need sources in $target_name listing the source files")
assert(defined(invoker.outputs),
"Need asar name (as 1-element array, e.g. \$root_out_dir/foo.asar)")
assert(defined(invoker.root), "Need asar root directory")
asar_root = invoker.root
assert(defined(invoker.root), "Need the base dir for generating the ASAR")

# js2asar.py expects relative paths to its inputs, so we must run it in a
# working directory in which those relative paths make sense.
chdir_action(target_name) {
sources = invoker.sources
outputs = invoker.outputs
script = "//electron/tools/js2asar.py"
cwd = rebase_path(get_path_info(".", "abspath"))
args = rebase_path(outputs, cwd) + [ asar_root ] + rebase_path(sources, ".")
node_action(target_name) {
forward_variables_from(invoker,
"*",
[
"script",
"args",
])

script = "//electron/script/gn-asar.js"
args = [
"--base",
rebase_path(root),
"--files",
] + rebase_path(sources) +
[
"--out",
rebase_path(outputs[0]),
]
}
}
@@ -0,0 +1,21 @@
template("node_action") {
assert(defined(invoker.script), "Need script path to run")
assert(defined(invoker.args), "Need script argumets")

action(target_name) {
forward_variables_from(invoker,
[
"deps",
"public_deps",
"sources",
"inputs",
"outputs",
])
if (!defined(inputs)) {
inputs = []
}
inputs += [ invoker.script ]
script = "//electron/build/run-node.py"
args = [ rebase_path(invoker.script) ] + invoker.args
}
}
@@ -0,0 +1,14 @@
import os
import subprocess
import sys


SOURCE_ROOT = os.path.dirname(os.path.dirname(__file__))

def main():
# Proxy all args to node script
script = os.path.join(SOURCE_ROOT, sys.argv[1])
subprocess.check_call(['node', script] + [str(x) for x in sys.argv[2:]])

if __name__ == '__main__':
sys.exit(main())
@@ -4,7 +4,7 @@
<title>Electron</title>
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'" />
<link href="./styles.css" type="text/css" rel="stylesheet" />
<link href="./node_modules/octicons/build/build.css" type="text/css" rel="stylesheet" />
<link href="./octicon/build.css" type="text/css" rel="stylesheet" />
</head>

<body>
@@ -35,7 +35,7 @@ function initialize () {
document.querySelector('.command-example').innerText = `${electronPath} path-to-app`

function getOcticonSvg (name) {
const octiconPath = path.resolve(__dirname, 'node_modules', 'octicons', 'build', 'svg', `${name}.svg`)
const octiconPath = path.resolve(__dirname, 'octicon', `${name}.svg`)
if (fs.existsSync(octiconPath)) {
const content = fs.readFileSync(octiconPath, 'utf8')
const div = document.createElement('div')
@@ -99,6 +99,9 @@ filenames = {
"default_app/package.json",
"default_app/renderer.js",
"default_app/styles.css",
]

default_app_octicon_sources = [
"node_modules/octicons/build/build.css",
"node_modules/octicons/build/svg/gist.svg",
"node_modules/octicons/build/svg/mark-github.svg",
@@ -0,0 +1,61 @@
const asar = require('asar')
const assert = require('assert')
const fs = require('fs-extra')
const os = require('os')
const path = require('path')

const getArgGroup = (name) => {
const group = []
let inGroup = false
for (const arg of process.argv) {
// At the next flag we stop being in the current group
if (arg.startsWith('--')) inGroup = false
// Push all args in the group
if (inGroup) group.push(arg)
// If we find the start flag, start pushing
if (arg === `--${name}`) inGroup = true
}

return group
}

const base = getArgGroup('base')
const files = getArgGroup('files')
const out = getArgGroup('out')

assert(base.length === 1, 'should have a single base dir')
assert(files.length >= 1, 'should have at least one input file')
assert(out.length === 1, 'should have a single out path')

// Ensure all files are inside the base dir
for (const file of files) {
if (!file.startsWith(base[0])) {
console.error(`Expected all files to be inside the base dir but "${file}" was not in "${base[0]}"`)
process.exit(1)
}
}

const tmpPath = fs.mkdtempSync(path.resolve(os.tmpdir(), 'electron-gn-asar-'))

try {
// Copy all files to a tmp dir to avoid including scrap files in the ASAR
for (const file of files) {
const newLocation = path.resolve(tmpPath, path.relative(base[0], file))
fs.mkdirsSync(path.dirname(newLocation))
fs.writeFileSync(newLocation, fs.readFileSync(file))
}
} catch (err) {
console.error('Unexpected error while generating ASAR', err)
fs.removeSync(tmpPath)
process.exit(1)
}

// Create the ASAR archive
asar.createPackageWithOptions(tmpPath, out[0], {}, (err) => {
fs.removeSync(tmpPath)

if (err) {
console.error('Unexpected error while generating ASAR', err)
process.exit(1)
}
})

This file was deleted.

Oops, something went wrong.

0 comments on commit b202ad1

Please sign in to comment.