Merge branch 'master' into ns-modernize-build

This commit is contained in:
Nathan Sobo
2016-08-05 16:34:48 -06:00
11 changed files with 162 additions and 271 deletions

View File

@@ -5,11 +5,12 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
## Requirements
* OS with 64-bit or 32-bit architecture
* C++ toolchain
* C++11 toolchain
* [Git](https://git-scm.com/)
* [Node.js](https://nodejs.org/en/download/) (0.10.x or above)
* [npm](https://www.npmjs.com/) v1.4.x or above (automatically bundled with Node.js)
* Node.js (4.x or above) (Can be installed via [nvm](https://github.com/creationix/nvm)).
* [npm](https://www.npmjs.com/) v3.10.5 or above (automatically bundled with Node.js)
* `npm -v` to check the version.
* `npm install -g npm` to upgrade if necessary.
* `npm config set python /usr/bin/python2 -g` to ensure that gyp uses python2.
* You might need to run this command as `sudo`, depending on how you have set up [npm](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os).
* development headers for [GNOME Keyring](https://wiki.gnome.org/Projects/GnomeKeyring)
@@ -17,10 +18,18 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
### Ubuntu / Debian
* `sudo apt-get install build-essential git libgnome-keyring-dev fakeroot`
* Instructions for [Node.js](https://github.com/nodejs/node-v0.x-archive/wiki/Installing-Node.js-via-package-manager#debian-and-ubuntu-based-linux-distributions).
* Make sure the command `node` is available after Node.js installation (some systems install it as `nodejs`).
* Use `which node` to check if it is available.
* Use `sudo update-alternatives --install /usr/bin/node node /usr/bin/nodejs 10` to update it.
* Install Node.js and npm:
* Install [nvm](https://github.com/creationix/nvm).
* Run `nvm install 4` to install Node 4.x.
* Run `npm install -g npm` to upgrade to the latest npm.
* You may need to install a newer C++ compiler with C++11 support if script/bootstrap has errors:
```sh
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install gcc-5 g++-5
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 80 --slave /usr/bin/g++ g++ /usr/bin/g++-5
sudo update-alternatives --config gcc # choose gcc-5 from the list
```
### Fedora / CentOS / RHEL

View File

@@ -58,7 +58,7 @@
"sinon": "1.17.4",
"source-map-support": "^0.3.2",
"temp": "0.8.1",
"text-buffer": "9.2.3",
"text-buffer": "9.2.6",
"typescript-simple": "1.0.0",
"underscore-plus": "^1.6.6",
"winreg": "^1.2.1",
@@ -87,13 +87,13 @@
"autoflow": "0.27.0",
"autosave": "0.23.1",
"background-tips": "0.26.1",
"bookmarks": "0.41.0",
"bookmarks": "0.41.1",
"bracket-matcher": "0.82.1",
"command-palette": "0.38.0",
"deprecation-cop": "0.54.1",
"dev-live-reload": "0.47.0",
"encoding-selector": "0.22.0",
"exception-reporting": "0.38.1",
"exception-reporting": "0.38.3",
"find-and-replace": "0.201.0",
"fuzzy-finder": "1.3.0",
"git-diff": "1.1.0",

View File

@@ -197,6 +197,21 @@ class AtomReporter
time = "0#{time}" if time.length < 3
@time.textContent = "#{time[0...-2]}.#{time[-2..]}s"
specTitle: (spec) ->
parentDescs = []
s = spec.suite
while s
parentDescs.unshift(s.description)
s = s.parentSuite
suiteString = ""
indent = ""
for desc in parentDescs
suiteString += indent + desc + "\n"
indent += " "
"#{suiteString} #{indent} it #{spec.description}"
addSpecs: (specs) ->
coreSpecs = 0
bundledPackageSpecs = 0
@@ -204,6 +219,7 @@ class AtomReporter
for spec in specs
symbol = document.createElement('li')
symbol.setAttribute('id', "spec-summary-#{spec.id}")
symbol.setAttribute('title', @specTitle(spec))
symbol.className = "spec-summary pending"
switch spec.specType
when 'core'

View File

@@ -1,159 +1,85 @@
'use babel'
/** @babel */
/* eslint-env jasmine */
import child_process from 'child_process'
import environmentHelpers from '../src/environment-helpers'
import os from 'os'
import updateProcessEnv from '../src/update-process-env'
import dedent from 'dedent'
describe('Environment handling', () => {
let originalEnv
let options
describe('updateProcessEnv(launchEnv)', function () {
let originalProcessEnv, originalProcessPlatform
beforeEach(() => {
originalEnv = process.env
delete process._originalEnv
options = {
platform: process.platform,
env: Object.assign({}, process.env)
}
beforeEach(function () {
originalProcessEnv = process.env
originalProcessPlatform = process.platform
process.env = {}
})
afterEach(() => {
process.env = originalEnv
delete process._originalEnv
afterEach(function () {
process.env = originalProcessEnv
process.platform = originalProcessPlatform
})
describe('on macOS, when PWD is not set', () => {
beforeEach(() => {
options.platform = 'darwin'
})
describe('when the launch environment appears to come from a shell', function () {
it('updates process.env to match the launch environment', function () {
process.env = {
WILL_BE_DELETED: 'hi',
NODE_ENV: 'the-node-env',
NODE_PATH: '/the/node/path',
}
const initialProcessEnv = process.env
describe('needsPatching', () => {
it('returns true if PWD is unset', () => {
delete options.env.PWD
expect(environmentHelpers.needsPatching(options)).toBe(true)
options.env.PWD = undefined
expect(environmentHelpers.needsPatching(options)).toBe(true)
options.env.PWD = null
expect(environmentHelpers.needsPatching(options)).toBe(true)
options.env.PWD = false
expect(environmentHelpers.needsPatching(options)).toBe(true)
updateProcessEnv({PWD: '/the/dir', KEY1: 'value1', KEY2: 'value2'})
expect(process.env).toEqual({
PWD: '/the/dir',
KEY1: 'value1',
KEY2: 'value2',
NODE_ENV: 'the-node-env',
NODE_PATH: '/the/node/path',
})
it('returns false if PWD is set', () => {
options.env.PWD = 'xterm'
expect(environmentHelpers.needsPatching(options)).toBe(false)
})
})
describe('normalize', () => {
it('changes process.env if PWD is unset', () => {
if (process.platform === 'win32') {
return
}
delete options.env.PWD
environmentHelpers.normalize(options)
expect(process._originalEnv).toBeDefined()
expect(process._originalEnv).toBeTruthy()
expect(process.env).toBeDefined()
expect(process.env).toBeTruthy()
expect(process.env.PWD).toBeDefined()
expect(process.env.PWD).toBeTruthy()
expect(process.env.PATH).toBeDefined()
expect(process.env.PATH).toBeTruthy()
expect(process.env.ATOM_HOME).toBeDefined()
expect(process.env.ATOM_HOME).toBeTruthy()
})
// See #11302. On Windows, `process.env` is a magic object that offers
// case-insensitive environment variable matching, so we cannot replace it
// with another object.
expect(process.env).toBe(initialProcessEnv)
})
})
describe('on a platform other than macOS', () => {
beforeEach(() => {
options.platform = 'penguin'
})
describe('when the launch environment does not come from a shell', function () {
describe('on osx', function () {
it('updates process.env to match the environment in the user\'s login shell', function () {
process.platform = 'darwin'
process.env.SHELL = '/my/custom/bash'
describe('needsPatching', () => {
it('returns false if PWD is set or unset', () => {
delete options.env.PWD
expect(environmentHelpers.needsPatching(options)).toBe(false)
options.env.PWD = undefined
expect(environmentHelpers.needsPatching(options)).toBe(false)
options.env.PWD = null
expect(environmentHelpers.needsPatching(options)).toBe(false)
options.env.PWD = false
expect(environmentHelpers.needsPatching(options)).toBe(false)
options.env.PWD = '/'
expect(environmentHelpers.needsPatching(options)).toBe(false)
})
it('returns false for linux', () => {
options.platform = 'linux'
options.PWD = '/'
expect(environmentHelpers.needsPatching(options)).toBe(false)
})
it('returns false for windows', () => {
options.platform = 'win32'
options.PWD = 'c:\\'
expect(environmentHelpers.needsPatching(options)).toBe(false)
})
})
describe('normalize', () => {
it('does not change the environment', () => {
if (process.platform === 'win32') {
return
}
delete options.env.PWD
environmentHelpers.normalize(options)
expect(process._originalEnv).toBeUndefined()
expect(process.env).toBeDefined()
expect(process.env).toBeTruthy()
expect(process.env.PATH).toBeDefined()
expect(process.env.PATH).toBeTruthy()
expect(process.env.PWD).toBeUndefined()
expect(process.env.PATH).toBe(originalEnv.PATH)
expect(process.env.ATOM_HOME).toBeDefined()
expect(process.env.ATOM_HOME).toBeTruthy()
})
})
})
describe('getFromShell', () => {
describe('when things are configured properly', () => {
beforeEach(() => {
spyOn(child_process, 'spawnSync').andReturn({
stdout: 'FOO=BAR' + os.EOL + 'TERM=xterm-something' + os.EOL +
'PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path'
stdout: dedent`
FOO=BAR=BAZ=QUUX
TERM=xterm-something
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path
`
})
})
it('returns an object containing the information from the user\'s shell environment', () => {
let env = environmentHelpers.getFromShell()
expect(env.FOO).toEqual('BAR')
expect(env.TERM).toEqual('xterm-something')
expect(env.PATH).toEqual('/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path')
updateProcessEnv(process.env)
expect(child_process.spawnSync.mostRecentCall.args[0]).toBe('/my/custom/bash')
expect(process.env).toEqual({
FOO: 'BAR=BAZ=QUUX',
TERM: 'xterm-something',
PATH: '/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path'
})
// Doesn't error
updateProcessEnv(null)
})
})
describe('when an error occurs launching the shell', () => {
beforeEach(() => {
spyOn(child_process, 'spawnSync').andReturn({
error: new Error('testing when an error occurs')
})
})
describe('not on osx', function () {
it('does not update process.env', function () {
process.platform = 'win32'
spyOn(child_process, 'spawnSync')
process.env = {FOO: 'bar'}
it('returns undefined', () => {
expect(environmentHelpers.getFromShell()).toBeUndefined()
})
it('leaves the environment as-is when normalize() is called', () => {
options.platform = 'darwin'
delete options.env.PWD
expect(environmentHelpers.needsPatching(options)).toBe(true)
environmentHelpers.normalize(options)
expect(process.env).toBeDefined()
expect(process._originalEnv).toBeUndefined()
updateProcessEnv(process.env)
expect(child_process.spawnSync).not.toHaveBeenCalled()
expect(process.env).toEqual({FOO: 'bar'})
})
})
})

View File

@@ -5901,6 +5901,13 @@ describe "TextEditor", ->
rangeIsReversed: false
}
it "does not throw errors after the marker's containing layer is destroyed", ->
layer = editor.addMarkerLayer()
marker = layer.markBufferRange([[2, 4], [6, 8]])
decoration = editor.decorateMarker(marker, type: 'highlight', class: 'foo')
layer.destroy()
editor.decorationsStateForScreenRowRange(0, 5)
describe "::decorateMarkerLayer", ->
it "based on the markers in the layer, includes multiple decoration objects with the same properties and different ranges in the object returned from ::decorationsStateForScreenRowRange", ->
layer1 = editor.getBuffer().addMarkerLayer()

View File

@@ -144,7 +144,7 @@ class DecorationManager extends Model
else
delete @overlayDecorationsById[decoration.id]
didDestroyDecoration: (decoration) ->
didDestroyMarkerDecoration: (decoration) ->
{marker} = decoration
return unless decorations = @decorationsByMarkerId[marker.id]
index = decorations.indexOf(decoration)

View File

@@ -69,16 +69,16 @@ class Decoration
@destroyed = false
@markerDestroyDisposable = @marker.onDidDestroy => @destroy()
# Essential: Destroy this marker.
# Essential: Destroy this marker decoration.
#
# If you own the marker, you should use {DisplayMarker::destroy} which will destroy
# this decoration.
# You can also destroy the marker if you own it, which will destroy this
# decoration.
destroy: ->
return if @destroyed
@markerDestroyDisposable.dispose()
@markerDestroyDisposable = null
@destroyed = true
@decorationManager.didDestroyDecoration(this)
@decorationManager.didDestroyMarkerDecoration(this)
@emitter.emit 'did-destroy'
@emitter.dispose()

View File

@@ -1,116 +0,0 @@
'use babel'
import {spawnSync} from 'child_process'
import os from 'os'
// Gets a dump of the user's configured shell environment.
//
// Returns the output of the `env` command or `undefined` if there was an error.
function getRawShellEnv () {
let shell = getUserShell()
// The `-ilc` set of options was tested to work with the macOS v10.11
// default-installed versions of bash, zsh, sh, and ksh. It *does not*
// work with csh or tcsh.
let results = spawnSync(shell, ['-ilc', 'env'], {encoding: 'utf8'})
if (results.error || !results.stdout || results.stdout.length <= 0) {
return
}
return results.stdout
}
function getUserShell () {
if (process.env.SHELL) {
return process.env.SHELL
}
return '/bin/bash'
}
// Gets the user's configured shell environment.
//
// Returns a copy of the user's shell enviroment.
function getFromShell () {
let shellEnvText = getRawShellEnv()
if (!shellEnvText) {
return
}
let env = {}
for (let line of shellEnvText.split(os.EOL)) {
if (line.includes('=')) {
let components = line.split('=')
if (components.length === 2) {
env[components[0]] = components[1]
} else {
let k = components.shift()
let v = components.join('=')
env[k] = v
}
}
}
return env
}
function needsPatching (options = { platform: process.platform, env: process.env }) {
if (options.platform === 'darwin' && !options.env.PWD) {
let shell = getUserShell()
if (shell.endsWith('csh') || shell.endsWith('tcsh') || shell.endsWith('fish')) {
return false
}
return true
}
return false
}
// Fix for #11302 because `process.env` on Windows is a magic object that offers case-insensitive
// environment variable matching. By always cloning to `process.env` we prevent breaking the
// underlying functionality.
function clone (to, from) {
for (var key in to) {
// Don't erase NODE_ENV. Fixes #12024
if (key !== 'NODE_ENV') {
delete to[key]
}
}
Object.assign(to, from)
}
function normalize (options = {}) {
if (options && options.env) {
clone(process.env, options.env)
}
if (!options.env) {
options.env = process.env
}
if (!options.platform) {
options.platform = process.platform
}
if (needsPatching(options)) {
// Patch the `process.env` on startup to fix the problem first documented
// in #4126. Retain the original in case someone needs it.
let shellEnv = getFromShell()
if (shellEnv && shellEnv.PATH) {
process._originalEnv = Object.assign({}, process.env)
clone(process.env, shellEnv)
}
}
}
function replace (env) {
if (!env || !env.PATH) {
return
}
clone(process.env, env)
}
export default { getFromShell, needsPatching, normalize, replace }

View File

@@ -1,15 +1,13 @@
# Like sands through the hourglass, so are the days of our lives.
module.exports = ({blobStore}) ->
environmentHelpers = require('./environment-helpers')
updateProcessEnv = require('./update-process-env')
path = require 'path'
require './window'
{getWindowLoadSettings} = require './window-load-settings-helpers'
{ipcRenderer} = require 'electron'
{resourcePath, isSpec, devMode, env} = getWindowLoadSettings()
# Set baseline environment
environmentHelpers.normalize({env: env})
env = process.env
updateProcessEnv(env)
# Add application-specific exports to module search path.
exportsPath = path.join(resourcePath, 'exports')
@@ -37,5 +35,5 @@ module.exports = ({blobStore}) ->
setTimeout (-> document.querySelector('atom-workspace').focus()), 0
window.addEventListener('focus', windowFocused)
ipcRenderer.on('environment', (event, env) ->
environmentHelpers.replace(env)
updateProcessEnv(env)
)

View File

@@ -113,9 +113,11 @@ function setupAtomHome ({setPortable}) {
try {
atomHome = fs.realpathSync(atomHome)
} finally {
process.env.ATOM_HOME = atomHome
} catch (e) {
// Don't throw an error if atomHome doesn't exist.
}
process.env.ATOM_HOME = atomHome
}
function setupCompileCache () {

49
src/update-process-env.js Normal file
View File

@@ -0,0 +1,49 @@
/** @babel */
import {spawnSync} from 'child_process'
const ENVIRONMENT_VARIABLES_TO_PRESERVE = new Set(['NODE_ENV', 'NODE_PATH'])
export default function updateProcessEnv (launchEnv) {
let envToAssign
if (launchEnv && launchEnv.PWD) {
envToAssign = launchEnv
} else {
if (process.platform === 'darwin') {
envToAssign = getEnvFromShell()
}
}
if (envToAssign) {
for (let key in process.env) {
if (!ENVIRONMENT_VARIABLES_TO_PRESERVE.has(key)) {
delete process.env[key]
}
}
for (let key in envToAssign) {
if (!ENVIRONMENT_VARIABLES_TO_PRESERVE.has(key)) {
process.env[key] = envToAssign[key]
}
}
}
}
function getEnvFromShell () {
let shell = process.env.SHELL
if (shell && (shell.endsWith('/bash') || shell.endsWith('/sh'))) {
let {stdout} = spawnSync(shell, ['-ilc', 'env'], {encoding: 'utf8'})
if (stdout) {
let result = {}
for (let line of stdout.split('\n')) {
if (line.includes('=')) {
let components = line.split('=')
let key = components.shift()
let value = components.join('=')
result[key] = value
}
}
return result
}
}
}