├── .gitignore
├── .travis.yml
├── downloaded
└── readme.md
├── collaborators.md
├── cli.js
├── package.json
├── readme.md
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | downloaded/*.zip
2 | node_modules
3 | .DS_Store
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '0.12'
4 |
--------------------------------------------------------------------------------
/downloaded/readme.md:
--------------------------------------------------------------------------------
1 | downloaded atom shell zips get cached here
--------------------------------------------------------------------------------
/collaborators.md:
--------------------------------------------------------------------------------
1 | ## Collaborators
2 |
3 | atom-shell-packager is only possible due to the excellent work of the following collaborators:
4 |
5 |
9 |
--------------------------------------------------------------------------------
/cli.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | var args = require('minimist')(process.argv.slice(2))
3 | var packager = require('./')
4 |
5 | args.dir = args._[0]
6 | args.name = args._[1]
7 |
8 | var protocolSchemes = [].concat(args.protocol || [])
9 | var protocolNames = [].concat(args['protocol-name'] || [])
10 |
11 | if (protocolSchemes && protocolNames && protocolNames.length === protocolSchemes.length) {
12 | args.protocols = protocolSchemes.map(function (scheme, i) {
13 | return {schemes: [scheme], name: protocolNames[i]}
14 | })
15 | }
16 |
17 | if (!args.dir || !args.name) {
18 | console.error('Usage: atom-shell-packager ')
19 | process.exit(1)
20 | }
21 |
22 | packager(args, function done (err, appPath) {
23 | if (err) {
24 | console.error(err)
25 | process.exit(1)
26 | }
27 |
28 | console.error('Wrote new app to', appPath)
29 | })
30 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "atom-shell-packager",
3 | "version": "2.1.1",
4 | "description": "package and distribute your atom-shell app in OS executables (.app, .exe, etc) via JS or CLI",
5 | "main": "index.js",
6 | "bin": {
7 | "atom-shell-packager": "cli.js"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/maxogden/atom-shell-packager.git"
12 | },
13 | "author": "max ogden",
14 | "license": "BSD",
15 | "bugs": {
16 | "url": "https://github.com/maxogden/atom-shell-packager/issues"
17 | },
18 | "homepage": "https://github.com/maxogden/atom-shell-packager",
19 | "dependencies": {
20 | "minimist": "^1.1.1",
21 | "mkdirp": "^0.5.0",
22 | "ncp": "^2.0.0",
23 | "plist": "^1.1.0",
24 | "rimraf": "^2.3.2"
25 | },
26 | "devDependencies": {
27 | "standard": "^3.3.2"
28 | },
29 | "scripts": {
30 | "test": "standard"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # atom-shell-packager
2 |
3 | Build a distributable app from an atom-shell app source code directory. **Currently only Mac OS is implemented** but you can send PRs to implement windows/linux :)
4 |
5 | [](https://nodei.co/npm/atom-shell-packager/)
6 |
7 | [](https://travis-ci.org/maxogden/atom-shell-packager)
8 |
9 | For an example project using this, check out [Monu](https://github.com/maxogden/monu)
10 |
11 | ### installation
12 |
13 | ```
14 | # for use in npm scripts
15 | npm i atom-shell-packager --save-dev
16 |
17 | # for use from cli
18 | npm i atom-shell-packager -g
19 |
20 | # you also need atom-shell installed
21 | npm i atom-shell
22 | ```
23 |
24 | ### usage
25 |
26 | ```
27 | $ atom-shell-packager my-app-source-dir AppName
28 | ```
29 |
30 | This will:
31 |
32 | - Find the closest local version of `atom-shell` installed (using `require.resolve`)
33 | - Use that version of atom-shell to create a Mac app in `cwd` called `AppName.app`
34 |
35 | You should be able to double-click `AppName.app` to launch the app. If not, check your settings and try again.
36 |
37 | **Be careful** not to include node_modules you don't want into your final app. For example, do not include the `node_modules/atom-shell-packager` folder or `node_modules/atom-shell`. You can use `--ignore=node_modules/atom-shell` to ignore of these
38 |
39 | ### options
40 |
41 | these are optional CLI options you can pass in
42 |
43 | - `out` (default current working dir) - the dir to put the app into at the end
44 | - `version` (default hardcoded in source) - atom-shell version to use
45 | - `app-bundle-id` - bundle identifier to use in the app plist
46 | - `helper-bundle-id` - bundle identifier to use in the app helper plist
47 | - `ignore` (default none) - do not copy files into App whose filenames regex .match this string
48 | - `prune` - runs `npm prune --production` on the app
49 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var os = require('os')
2 | var path = require('path')
3 | var fs = require('fs')
4 | var child = require('child_process')
5 |
6 | var plist = require('plist')
7 | var mkdirp = require('mkdirp')
8 | var rimraf = require('rimraf')
9 | var ncp = require('ncp').ncp
10 |
11 | module.exports = function packager (opts, cb) {
12 | var atomShellPath
13 |
14 | try {
15 | atomShellPath = require.resolve('atom-shell')
16 | atomShellPath = path.join(atomShellPath, '..')
17 | } catch (e) {
18 | try {
19 | atomShellPath = require.resolve(path.join(process.execPath, '../../lib/node_modules/atom-shell'))
20 | atomShellPath = path.join(atomShellPath, '..')
21 | } catch (e) {
22 | cb(new Error('Cannot find atom-shell from here, please install it from npm'))
23 | }
24 | }
25 |
26 | var atomPkg = require(path.join(atomShellPath, 'package.json'))
27 | console.error('Using atom-shell version', atomPkg.version, 'from', atomShellPath)
28 |
29 | var atomShellApp = path.join(atomShellPath, 'dist', 'Atom.app')
30 | var tmpDir = path.join(os.tmpdir(), 'atom-shell-packager-mac')
31 |
32 | var newApp = path.join(tmpDir, opts.name + '.app')
33 |
34 | // reset build folders + copy template app
35 | rimraf(tmpDir, function rmrfd () {
36 | // ignore errors
37 | mkdirp(newApp, function mkdirpd () {
38 | // ignore errors
39 | // copy .app folder and use as template (this is exactly what Atom editor does)
40 | ncp(atomShellApp, newApp, function copied (err) {
41 | if (err) return cb(err)
42 | buildMacApp()
43 | })
44 | })
45 | })
46 |
47 | function buildMacApp () {
48 | var paths = {
49 | info1: path.join(newApp, 'Contents', 'Info.plist'),
50 | info2: path.join(newApp, 'Contents', 'Frameworks', 'Atom Helper.app', 'Contents', 'Info.plist'),
51 | app: path.join(newApp, 'Contents', 'Resources', 'app')
52 | }
53 |
54 | // update plist files
55 | var pl1 = plist.parse(fs.readFileSync(paths.info1).toString())
56 | var pl2 = plist.parse(fs.readFileSync(paths.info2).toString())
57 |
58 | var bundleId = opts['app-bundle-id'] || 'com.atom-shell.' + opts.name.toLowerCase()
59 | var bundleHelperId = opts['helper-bundle-id'] || 'com.atom-shell.' + opts.name.toLowerCase() + '.helper'
60 |
61 | pl1.CFBundleDisplayName = opts.name
62 | pl1.CFBundleIdentifier = bundleId
63 | pl1.CFBundleName = opts.name
64 | pl2.CFBundleIdentifier = bundleHelperId
65 | pl2.CFBundleName = opts.name
66 |
67 | if (opts.protocols) {
68 | pl2.CFBundleURLTypes = pl1.CFBundleURLTypes = opts.protocols.map(function (protocol) {
69 | return {
70 | CFBundleURLName: protocol.name,
71 | CFBundleURLSchemes: [].concat(protocol.schemes)
72 | }
73 | })
74 | }
75 |
76 | fs.writeFileSync(paths.info1, plist.build(pl1))
77 | fs.writeFileSync(paths.info2, plist.build(pl2))
78 |
79 | function filter (file) {
80 | var ignore = opts.ignore || []
81 | if (!Array.isArray(ignore)) ignore = [ignore]
82 | for (var i = 0; i < ignore.length; i++) {
83 | if (file.match(ignore[i])) {
84 | return false
85 | }
86 | }
87 | return true
88 | }
89 |
90 | // copy users app into .app
91 | ncp(opts.dir, paths.app, {filter: filter}, function copied (err) {
92 | if (err) return cb(err)
93 |
94 | if (opts.prune) {
95 | prune(function pruned (err) {
96 | if (err) return cb(err)
97 | moveApp()
98 | })
99 | } else {
100 | moveApp()
101 | }
102 |
103 | function prune (cb) {
104 | child.exec('npm prune --production', { cwd: paths.app }, cb)
105 | }
106 |
107 | function moveApp () {
108 | // finally, move app into cwd
109 | var finalPath = path.join(opts.out || process.cwd(), opts.name + '.app')
110 |
111 | fs.rename(newApp, finalPath, function moved (err) {
112 | cb(err, finalPath)
113 | })
114 | }
115 | })
116 | }
117 | }
118 |
--------------------------------------------------------------------------------