mirror of
https://github.com/atom/atom.git
synced 2026-01-22 21:38:10 -05:00
Merge branch 'master' into dh-async-repo
This commit is contained in:
@@ -38,7 +38,6 @@ module.exports = (grunt) ->
|
||||
buildDir = grunt.option('build-dir')
|
||||
buildDir ?= path.join(os.tmpdir(), 'atom-build')
|
||||
buildDir = path.resolve(buildDir)
|
||||
disableAutoUpdate = grunt.option('no-auto-update') ? false
|
||||
|
||||
channel = grunt.option('channel')
|
||||
releasableBranches = ['stable', 'beta']
|
||||
@@ -181,7 +180,7 @@ module.exports = (grunt) ->
|
||||
pkg: grunt.file.readJSON('package.json')
|
||||
|
||||
atom: {
|
||||
appName, channel, metadata, disableAutoUpdate,
|
||||
appName, channel, metadata,
|
||||
appFileName, apmFileName,
|
||||
appDir, buildDir, contentsDir, installDir, shellAppDir, symbolsDir,
|
||||
}
|
||||
@@ -257,7 +256,7 @@ module.exports = (grunt) ->
|
||||
outputDir: 'electron'
|
||||
downloadDir: electronDownloadDir
|
||||
rebuild: true # rebuild native modules after electron is updated
|
||||
token: process.env.ATOM_ACCESS_TOKEN
|
||||
token: process.env.ATOM_ACCESS_TOKEN ? 'da809a6077bb1b0aa7c5623f7b2d5f1fec2faae4'
|
||||
|
||||
'create-windows-installer':
|
||||
installer:
|
||||
|
||||
@@ -186,5 +186,4 @@ module.exports = (grunt) ->
|
||||
dependencies = ['compile', 'generate-license:save', 'generate-module-cache', 'compile-packages-slug']
|
||||
dependencies.push('copy-info-plist') if process.platform is 'darwin'
|
||||
dependencies.push('set-exe-icon') if process.platform is 'win32'
|
||||
dependencies.push('disable-autoupdate') if grunt.config.get('atom.disableAutoUpdate')
|
||||
grunt.task.run(dependencies...)
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
|
||||
grunt.registerTask 'disable-autoupdate', 'Set up disableAutoUpdate field in package.json file', ->
|
||||
appDir = fs.realpathSync(grunt.config.get('atom.appDir'))
|
||||
|
||||
metadata = grunt.file.readJSON(path.join(appDir, 'package.json'))
|
||||
metadata._disableAutoUpdate = grunt.config.get('atom.disableAutoUpdate')
|
||||
|
||||
grunt.file.write(path.join(appDir, 'package.json'), JSON.stringify(metadata))
|
||||
@@ -66,9 +66,9 @@
|
||||
"base16-tomorrow-dark-theme": "1.1.0",
|
||||
"base16-tomorrow-light-theme": "1.1.1",
|
||||
"one-dark-ui": "1.1.9",
|
||||
"one-dark-syntax": "1.1.1",
|
||||
"one-light-syntax": "1.1.1",
|
||||
"one-light-ui": "1.1.9",
|
||||
"one-dark-syntax": "1.1.2",
|
||||
"one-light-syntax": "1.1.2",
|
||||
"solarized-dark-syntax": "0.39.0",
|
||||
"solarized-light-syntax": "0.23.0",
|
||||
"about": "1.1.0",
|
||||
|
||||
@@ -872,6 +872,26 @@ describe "Config", ->
|
||||
atom.config.loadUserConfig()
|
||||
expect(atom.config.get("foo.bar")).toBe "baz"
|
||||
|
||||
describe "when the config file fails to load", ->
|
||||
addErrorHandler = null
|
||||
|
||||
beforeEach ->
|
||||
atom.notifications.onDidAddNotification addErrorHandler = jasmine.createSpy()
|
||||
spyOn(fs, "existsSync").andCallFake ->
|
||||
error = new Error()
|
||||
error.code = 'EPERM'
|
||||
throw error
|
||||
|
||||
it "creates a notification and does not try to save later changes to disk", ->
|
||||
load = -> atom.config.loadUserConfig()
|
||||
expect(load).not.toThrow()
|
||||
expect(addErrorHandler.callCount).toBe 1
|
||||
|
||||
atom.config.set("foo.bar", "baz")
|
||||
advanceClock(100)
|
||||
expect(atom.config.save).not.toHaveBeenCalled()
|
||||
expect(atom.config.get("foo.bar")).toBe "baz"
|
||||
|
||||
describe ".observeUserConfig()", ->
|
||||
updatedHandler = null
|
||||
|
||||
|
||||
@@ -103,8 +103,6 @@ class ApplicationMenu
|
||||
downloadingUpdateItem.visible = false
|
||||
installUpdateItem.visible = false
|
||||
|
||||
return if @autoUpdateManager.isDisabled()
|
||||
|
||||
switch state
|
||||
when 'idle', 'error', 'no-update-available'
|
||||
checkForUpdateItem.visible = true
|
||||
@@ -119,9 +117,10 @@ class ApplicationMenu
|
||||
#
|
||||
# Returns an Array of menu item Objects.
|
||||
getDefaultTemplate: ->
|
||||
template = [
|
||||
[
|
||||
label: "Atom"
|
||||
submenu: [
|
||||
{label: "Check for Update", metadata: {autoUpdate: true}}
|
||||
{label: 'Reload', accelerator: 'Command+R', click: => @focusedWindow()?.reload()}
|
||||
{label: 'Close Window', accelerator: 'Command+Shift+W', click: => @focusedWindow()?.close()}
|
||||
{label: 'Toggle Dev Tools', accelerator: 'Command+Alt+I', click: => @focusedWindow()?.toggleDevTools()}
|
||||
@@ -129,10 +128,6 @@ class ApplicationMenu
|
||||
]
|
||||
]
|
||||
|
||||
# Add `Check for Update` button if autoUpdateManager is enabled.
|
||||
template[0].submenu.unshift({label: "Check for Update", metadata: {autoUpdate: true}}) unless @autoUpdateManager.isDisabled()
|
||||
template
|
||||
|
||||
focusedWindow: ->
|
||||
_.find global.atomApplication.windows, (atomWindow) -> atomWindow.isFocused()
|
||||
|
||||
|
||||
@@ -74,8 +74,7 @@ class AtomApplication
|
||||
@pidsToOpenWindows = {}
|
||||
@windows = []
|
||||
|
||||
disableAutoUpdate = require(path.join(@resourcePath, 'package.json'))._disableAutoUpdate ? false
|
||||
@autoUpdateManager = new AutoUpdateManager(@version, options.test, disableAutoUpdate)
|
||||
@autoUpdateManager = new AutoUpdateManager(@version, options.test, @resourcePath)
|
||||
@applicationMenu = new ApplicationMenu(@version, @autoUpdateManager)
|
||||
@atomProtocolHandler = new AtomProtocolHandler(@resourcePath, @safeMode)
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
autoUpdater = null
|
||||
_ = require 'underscore-plus'
|
||||
Config = require '../config'
|
||||
{EventEmitter} = require 'events'
|
||||
path = require 'path'
|
||||
|
||||
@@ -15,10 +16,13 @@ module.exports =
|
||||
class AutoUpdateManager
|
||||
_.extend @prototype, EventEmitter.prototype
|
||||
|
||||
constructor: (@version, @testMode, @disabled) ->
|
||||
constructor: (@version, @testMode, resourcePath) ->
|
||||
@state = IdleState
|
||||
@iconPath = path.resolve(__dirname, '..', '..', 'resources', 'atom.png')
|
||||
@feedUrl = "https://atom.io/api/updates?version=#{@version}"
|
||||
@config = new Config({configDirPath: process.env.ATOM_HOME, resourcePath, enablePersistence: true})
|
||||
@config.setSchema null, {type: 'object', properties: _.clone(require('../config-schema'))}
|
||||
@config.load()
|
||||
process.nextTick => @setupAutoUpdater()
|
||||
|
||||
setupAutoUpdater: ->
|
||||
@@ -46,9 +50,13 @@ class AutoUpdateManager
|
||||
@setState(UpdateAvailableState)
|
||||
@emitUpdateAvailableEvent(@getWindows()...)
|
||||
|
||||
# Only check for updates periodically if enabled and running in release
|
||||
# version.
|
||||
@scheduleUpdateCheck() unless /\w{7}/.test(@version) or @disabled
|
||||
@config.onDidChange 'core.automaticallyUpdate', ({newValue}) =>
|
||||
if newValue
|
||||
@scheduleUpdateCheck()
|
||||
else
|
||||
@cancelScheduledUpdateCheck()
|
||||
|
||||
@scheduleUpdateCheck() if @config.get 'core.automaticallyUpdate'
|
||||
|
||||
switch process.platform
|
||||
when 'win32'
|
||||
@@ -56,9 +64,6 @@ class AutoUpdateManager
|
||||
when 'linux'
|
||||
@setState(UnsupportedState)
|
||||
|
||||
isDisabled: ->
|
||||
@disabled
|
||||
|
||||
emitUpdateAvailableEvent: (windows...) ->
|
||||
return unless @releaseVersion?
|
||||
for atomWindow in windows
|
||||
@@ -74,10 +79,18 @@ class AutoUpdateManager
|
||||
@state
|
||||
|
||||
scheduleUpdateCheck: ->
|
||||
checkForUpdates = => @check(hidePopups: true)
|
||||
fourHours = 1000 * 60 * 60 * 4
|
||||
setInterval(checkForUpdates, fourHours)
|
||||
checkForUpdates()
|
||||
# Only schedule update check periodically if running in release version and
|
||||
# and there is no existing scheduled update check.
|
||||
unless /\w{7}/.test(@version) or @checkForUpdatesIntervalID
|
||||
checkForUpdates = => @check(hidePopups: true)
|
||||
fourHours = 1000 * 60 * 60 * 4
|
||||
@checkForUpdatesIntervalID = setInterval(checkForUpdates, fourHours)
|
||||
checkForUpdates()
|
||||
|
||||
cancelScheduledUpdateCheck: ->
|
||||
if @checkForUpdatesIntervalID
|
||||
clearInterval(@checkForUpdatesIntervalID)
|
||||
@checkForUpdatesIntervalID = null
|
||||
|
||||
check: ({hidePopups}={}) ->
|
||||
unless hidePopups
|
||||
|
||||
@@ -104,6 +104,10 @@ module.exports =
|
||||
description: 'Automatically open an empty editor on startup.'
|
||||
type: 'boolean'
|
||||
default: true
|
||||
automaticallyUpdate:
|
||||
description: 'Automatically update Atom when a new release is available.'
|
||||
type: 'boolean'
|
||||
default: true
|
||||
|
||||
editor:
|
||||
type: 'object'
|
||||
|
||||
@@ -779,9 +779,14 @@ class Config
|
||||
loadUserConfig: ->
|
||||
return if @shouldNotAccessFileSystem()
|
||||
|
||||
unless fs.existsSync(@configFilePath)
|
||||
fs.makeTreeSync(path.dirname(@configFilePath))
|
||||
CSON.writeFileSync(@configFilePath, {})
|
||||
try
|
||||
unless fs.existsSync(@configFilePath)
|
||||
fs.makeTreeSync(path.dirname(@configFilePath))
|
||||
CSON.writeFileSync(@configFilePath, {})
|
||||
catch error
|
||||
@configFileHasErrors = true
|
||||
@notifyFailure("Failed to initialize `#{path.basename(@configFilePath)}`", error.stack)
|
||||
return
|
||||
|
||||
try
|
||||
unless @savePending
|
||||
@@ -820,7 +825,7 @@ class Config
|
||||
@watchSubscription = null
|
||||
|
||||
notifyFailure: (errorMessage, detail) ->
|
||||
@notificationManager.addError(errorMessage, {detail, dismissable: true})
|
||||
@notificationManager?.addError(errorMessage, {detail, dismissable: true})
|
||||
|
||||
save: ->
|
||||
return if @shouldNotAccessFileSystem()
|
||||
|
||||
@@ -721,30 +721,28 @@ class Pane extends Model
|
||||
message = "#{message} '#{itemPath}'" if itemPath
|
||||
@notificationManager.addWarning(message, options)
|
||||
|
||||
if error.code is 'EISDIR' or error.message?.endsWith?('is a directory')
|
||||
customMessage = @getMessageForErrorCode(error.code)
|
||||
if customMessage?
|
||||
addWarningWithPath("Unable to save file: #{customMessage}")
|
||||
else if error.code is 'EISDIR' or error.message?.endsWith?('is a directory')
|
||||
@notificationManager.addWarning("Unable to save file: #{error.message}")
|
||||
else if error.code is 'EACCES'
|
||||
addWarningWithPath('Unable to save file: Permission denied')
|
||||
else if error.code in ['EPERM', 'EBUSY', 'UNKNOWN', 'EEXIST', 'ELOOP', 'EAGAIN']
|
||||
addWarningWithPath('Unable to save file', detail: error.message)
|
||||
else if error.code is 'EROFS'
|
||||
addWarningWithPath('Unable to save file: Read-only file system')
|
||||
else if error.code is 'ENOSPC'
|
||||
addWarningWithPath('Unable to save file: No space left on device')
|
||||
else if error.code is 'ENXIO'
|
||||
addWarningWithPath('Unable to save file: No such device or address')
|
||||
else if error.code is 'ENOTSUP'
|
||||
addWarningWithPath('Unable to save file: Operation not supported on socket')
|
||||
else if error.code is 'EIO'
|
||||
addWarningWithPath('Unable to save file: I/O error writing file')
|
||||
else if error.code is 'EINTR'
|
||||
addWarningWithPath('Unable to save file: Interrupted system call')
|
||||
else if error.code is 'ECONNRESET'
|
||||
addWarningWithPath('Unable to save file: Connection reset')
|
||||
else if error.code is 'ESPIPE'
|
||||
addWarningWithPath('Unable to save file: Invalid seek')
|
||||
else if errorMatch = /ENOTDIR, not a directory '([^']+)'/.exec(error.message)
|
||||
fileName = errorMatch[1]
|
||||
@notificationManager.addWarning("Unable to save file: A directory in the path '#{fileName}' could not be written to")
|
||||
else
|
||||
throw error
|
||||
|
||||
getMessageForErrorCode: (errorCode) ->
|
||||
switch errorCode
|
||||
when 'EACCES' then 'Permission denied'
|
||||
when 'ECONNRESET' then 'Connection reset'
|
||||
when 'EINTR' then 'Interrupted system call'
|
||||
when 'EIO' then 'I/O error writing file'
|
||||
when 'ENOSPC' then 'No space left on device'
|
||||
when 'ENOTSUP' then 'Operation not supported on socket'
|
||||
when 'ENXIO' then 'No such device or address'
|
||||
when 'EROFS' then 'Read-only file system'
|
||||
when 'ESPIPE' then 'Invalid seek'
|
||||
when 'ETIMEDOUT' then 'Connection timed out'
|
||||
|
||||
@@ -475,7 +475,7 @@ class Workspace extends Model
|
||||
when 'EACCES'
|
||||
@notificationManager.addWarning("Permission denied '#{error.path}'")
|
||||
return Promise.resolve()
|
||||
when 'EPERM', 'EBUSY', 'ENXIO', 'EIO', 'ENOTCONN', 'UNKNOWN', 'ECONNRESET', 'EINVAL', 'EMFILE', 'ENOTDIR'
|
||||
when 'EPERM', 'EBUSY', 'ENXIO', 'EIO', 'ENOTCONN', 'UNKNOWN', 'ECONNRESET', 'EINVAL', 'EMFILE', 'ENOTDIR', 'EAGAIN'
|
||||
@notificationManager.addWarning("Unable to open '#{error.path ? uri}'", detail: error.message)
|
||||
return Promise.resolve()
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user