diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ff48740b2..4ba9202df 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -221,6 +221,8 @@ Unsure where to begin contributing to Atom? You can start by looking through the Both issue lists are sorted by total number of comments. While not perfect, number of comments is a reasonable proxy for impact a given change will have. +If you want to read about using Atom or developing packages in Atom, the [Atom Flight Manual](http://flight-manual.atom.io) is free and available online. You can find the source to the manual in [atom/flight-manual.atom.io](https://github.com/atom/flight-manual.atom.io). + ### Pull Requests * Include screenshots and animated GIFs in your pull request whenever possible. diff --git a/README.md b/README.md index 20e940689..b31d0e58b 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ By participating, you are expected to uphold this code. Please report unacceptab ## Documentation -If you want to read about using Atom or developing packages in Atom, the [Atom Flight Manual](https://atom.io/docs/latest/) is free and available online, along with ePub, PDF and mobi versions. You can find the source to the manual in [atom/docs](https://github.com/atom/docs). +If you want to read about using Atom or developing packages in Atom, the [Atom Flight Manual](http://flight-manual.atom.io) is free and available online. You can find the source to the manual in [atom/flight-manual.atom.io](https://github.com/atom/flight-manual.atom.io). The [API reference](https://atom.io/docs/api) for developing packages is also documented on Atom.io. diff --git a/appveyor.yml b/appveyor.yml index 20211da8c..51e074a4c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -33,6 +33,8 @@ deploy: off artifacts: - path: out\**\AtomSetup.exe name: AtomSetup.exe + - path: out\**\AtomSetup.msi + name: AtomSetup.msi cache: - '%USERPROFILE%\.atom\.apm' diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index 16e0ed5d6..b248eda2e 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -172,6 +172,8 @@ module.exports = (grunt) -> dest: path.join(appDir, jsFile) }) + windowsInstallerConfig = + grunt.initConfig pkg: grunt.file.readJSON('package.json') @@ -286,12 +288,16 @@ module.exports = (grunt) -> ciTasks.push('set-version', 'check-licenses', 'lint', 'generate-asar') ciTasks.push('mkdeb') if process.platform is 'linux' ciTasks.push('mktar') if process.platform is 'linux' - ciTasks.push('codesign:exe') if process.platform is 'win32' and not process.env.CI - ciTasks.push('create-windows-installer:installer') if process.platform is 'win32' ciTasks.push('test') if process.platform is 'darwin' - ciTasks.push('codesign:installer') if process.platform is 'win32' and not process.env.CI ciTasks.push('codesign:app') if process.platform is 'darwin' and not process.env.CI + if process.platform is 'win32' + ciTasks.push('codesign:exe') if process.env.JANKY_SIGNTOOL + ciTasks.push('codesign:installer-deferred') if not process.env.JANKY_SIGNTOOL + ciTasks.push('create-windows-installer:installer') + ciTasks.push('codesign:installer') if process.env.JANKY_SIGNTOOL + ciTasks.push('codesign:cleanup') ciTasks.push('publish-build') unless process.env.CI + grunt.registerTask('ci', ciTasks) defaultTasks = ['download-electron', 'download-electron-chromedriver', 'build', 'set-version', 'generate-asar'] diff --git a/build/tasks/codesign-task.coffee b/build/tasks/codesign-task.coffee index 559d41bbf..13ea9f4df 100644 --- a/build/tasks/codesign-task.coffee +++ b/build/tasks/codesign-task.coffee @@ -5,46 +5,10 @@ request = require 'request' module.exports = (grunt) -> {spawn} = require('./task-helpers')(grunt) - signUsingWindowsSDK = (exeToSign, callback) -> - {WIN_P12KEY_PASSWORD, WIN_P12KEY_URL} = process.env - if WIN_P12KEY_URL? - grunt.log.ok("Obtaining signing key") - downloadedKeyFile = path.resolve(__dirname, 'DownloadedSignKey.p12') - downloadFile WIN_P12KEY_URL, downloadedKeyFile, (done) -> - signUsingWindowsSDKTool exeToSign, downloadedKeyFile, WIN_P12KEY_PASSWORD, (done) -> - fs.unlinkSync(downloadedKeyFile) - callback() - else - signUsingWindowsSDKTool exeToSign, path.resolve(__dirname, '..', 'certs', 'AtomDevTestSignKey.p12'), 'password', callback - - signUsingWindowsSDKTool = (exeToSign, keyFilePath, password, callback) -> - grunt.log.ok("Signing #{exeToSign}") - args = ['sign', '/v', '/p', password, '/f', keyFilePath, exeToSign] - spawn {cmd: 'C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.1A\\bin\\signtool.exe', args: args}, callback - - signUsingJanky = (exeToSign, callback) -> - spawn {cmd: process.env.JANKY_SIGNTOOL, args: [exeToSign]}, callback - - signWindowsExecutable = if process.env.JANKY_SIGNTOOL then signUsingJanky else signUsingWindowsSDK - - grunt.registerTask 'codesign:exe', 'CodeSign Atom.exe and Update.exe', -> - done = @async() - spawn {cmd: 'taskkill', args: ['/F', '/IM', 'atom.exe']}, -> - atomExePath = path.join(grunt.config.get('atom.shellAppDir'), 'atom.exe') - signWindowsExecutable atomExePath, (error) -> - return done(error) if error? - - updateExePath = path.resolve(__dirname, '..', 'node_modules', 'grunt-electron-installer', 'vendor', 'Update.exe') - signWindowsExecutable updateExePath, (error) -> done(error) - - grunt.registerTask 'codesign:installer', 'CodeSign AtomSetup.exe', -> - done = @async() - atomSetupExePath = path.resolve(grunt.config.get('atom.buildDir'), 'installer', 'AtomSetup.exe') - signWindowsExecutable atomSetupExePath, (error) -> done(error) + # Mac OS X code signing grunt.registerTask 'codesign:app', 'CodeSign Atom.app', -> done = @async() - unlockKeychain (error) -> return done(error) if error? @@ -53,11 +17,65 @@ module.exports = (grunt) -> unlockKeychain = (callback) -> return callback() unless process.env.XCODE_KEYCHAIN - {XCODE_KEYCHAIN_PASSWORD, XCODE_KEYCHAIN} = process.env args = ['unlock-keychain', '-p', XCODE_KEYCHAIN_PASSWORD, XCODE_KEYCHAIN] spawn {cmd: 'security', args: args}, (error) -> callback(error) + # Windows code signing + + grunt.registerTask 'codesign:exe', 'CodeSign Windows binaries', -> + done = @async() + atomExePath = path.join(grunt.config.get('atom.shellAppDir'), 'atom.exe') + signWindowsExecutable atomExePath, (error) -> + return done(error) if error? + updateExePath = path.resolve(__dirname, '..', 'node_modules', 'grunt-electron-installer', 'vendor', 'Update.exe') + signWindowsExecutable updateExePath, (error) -> done(error) + + grunt.registerTask 'codesign:installer', 'CodeSign Windows installer (AtomSetup.exe)', -> + done = @async() + atomSetupExePath = path.resolve(grunt.config.get('atom.buildDir'), 'installer', 'AtomSetup.exe') + signWindowsExecutable atomSetupExePath, (error) -> done(error) + + grunt.registerTask 'codesign:installer-deferred', 'Obtain cert and configure installer to perform CodeSign', -> + done = @async() + getCertificate (file, password) -> + grunt.config('create-windows-installer.installer.certificateFile', file) + grunt.config('create-windows-installer.installer.certificatePassword', password) + grunt.log.ok('Certificate ready for create-windows-installer task') + done() + + grunt.registerTask 'codesign:cleanup', 'Clean up any temporary or downloaded files used for CodeSign', -> + try fs.unlinkSync(downloadedCertificateFile) catch e then return + + downloadedCertificateFile = path.resolve(__dirname, 'DownloadedCertFile.p12') + + signWindowsExecutable = (exeToSign, callback) -> + if process.env.JANKY_SIGNTOOL + signUsingJanky exeToSign, callback + else + signUsingWindowsSDK exeToSign, callback + + signUsingJanky = (exeToSign, callback) -> + grunt.log.ok("Signing #{exeToSign} using Janky SignTool") + spawn {cmd: process.env.JANKY_SIGNTOOL, args: [exeToSign]}, callback + + signUsingWindowsSDK = (exeToSign, callback) -> + getCertificate (file, password) -> + signUsingWindowsSDKTool exeToSign, file, password, callback + + signUsingWindowsSDKTool = (exeToSign, certificateFile, certificatePassword, callback) -> + grunt.log.ok("Signing '#{exeToSign}' using Windows SDK") + args = ['sign', '/v', '/p', certificatePassword, '/f', certificateFile, exeToSign] + spawn {cmd: 'C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.1A\\bin\\signtool.exe', args: args}, callback + + getCertificate = (callback) -> + if process.env.WIN_P12KEY_URL? + grunt.log.ok("Obtaining certificate file") + downloadFile process.env.WIN_P12KEY_URL, downloadedCertificateFile, (done) -> + callback(downloadedCertificateFile, process.env.WIN_P12KEY_PASSWORD ? 'password') + else + callback(path.resolve(__dirname, '..', 'certs', 'AtomDevTestSignKey.p12'), process.env.WIN_P12KEY_PASSWORD ? 'password') + downloadFile = (sourceUrl, targetPath, callback) -> options = { url: sourceUrl diff --git a/package.json b/package.json index 3f8ab99ec..24be22395 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "marked": "^0.3.5", "normalize-package-data": "^2.0.0", "nslog": "^3", - "ohnogit": "0.0.11", + "ohnogit": "0.0.12", "oniguruma": "^5", "pathwatcher": "~6.5", "property-accessors": "^1.1.3", diff --git a/script/bootstrap b/script/bootstrap index 83ec712ff..3b9a35735 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -75,7 +75,7 @@ function bootstrap() { var buildInstallCommand = initialNpmCommand + npmFlags + 'install'; var buildInstallOptions = {cwd: path.resolve(__dirname, '..', 'build')}; - var apmInstallCommand = npmPath + npmFlags + '--target=0.10.35 ' + 'install'; + var apmInstallCommand = npmPath + npmFlags + '--target=0.10.40 ' + 'install'; var apmInstallOptions = {cwd: apmInstallPath}; var moduleInstallCommand = apmPath + ' install' + apmFlags; var dedupeApmCommand = apmPath + ' dedupe' + apmFlags; diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 72a919740..1b4537b2f 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -26,7 +26,7 @@ LocationSuffixRegExp = /(:\d+)(:\d+)?$/ # module.exports = class AtomApplication - _.extend @prototype, EventEmitter.prototype + Object.assign @prototype, EventEmitter.prototype # Public: The entry point into the Atom application. @open: (options) -> @@ -528,7 +528,7 @@ class AtomApplication restorePreviousState = @config.get('core.restorePreviousWindowsOnStart') ? true if restorePreviousState and (states = @storageFolder.load('application.json'))?.length > 0 for state in states - @openWithOptions(_.extend(options, { + @openWithOptions(Object.assign(options, { initialPaths: state.initialPaths pathsToOpen: state.initialPaths.filter (directoryPath) -> fs.isDirectorySync(directoryPath) urlsToOpen: [] diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index 236af4632..4954cf409 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -2,12 +2,11 @@ path = require 'path' fs = require 'fs' url = require 'url' -_ = require 'underscore-plus' {EventEmitter} = require 'events' module.exports = class AtomWindow - _.extend @prototype, EventEmitter.prototype + Object.assign @prototype, EventEmitter.prototype @iconPath: path.resolve(__dirname, '..', '..', 'resources', 'atom.png') @includeShellLoadTime: true @@ -46,7 +45,7 @@ class AtomWindow @handleEvents() - loadSettings = _.extend({}, settings) + loadSettings = Object.assign({}, settings) loadSettings.appVersion = app.getVersion() loadSettings.resourcePath = @resourcePath loadSettings.devMode ?= false diff --git a/src/browser/auto-update-manager.coffee b/src/browser/auto-update-manager.coffee index 602284b07..54f91dcd8 100644 --- a/src/browser/auto-update-manager.coffee +++ b/src/browser/auto-update-manager.coffee @@ -1,5 +1,4 @@ autoUpdater = null -_ = require 'underscore-plus' {EventEmitter} = require 'events' path = require 'path' @@ -13,7 +12,7 @@ ErrorState = 'error' module.exports = class AutoUpdateManager - _.extend @prototype, EventEmitter.prototype + Object.assign @prototype, EventEmitter.prototype constructor: (@version, @testMode, resourcePath, @config) -> @state = IdleState diff --git a/src/browser/auto-updater-win32.coffee b/src/browser/auto-updater-win32.coffee index e31578d49..ee49e5096 100644 --- a/src/browser/auto-updater-win32.coffee +++ b/src/browser/auto-updater-win32.coffee @@ -1,9 +1,8 @@ {EventEmitter} = require 'events' -_ = require 'underscore-plus' SquirrelUpdate = require './squirrel-update' class AutoUpdater - _.extend @prototype, EventEmitter.prototype + Object.assign @prototype, EventEmitter.prototype setFeedURL: (@updateUrl) -> diff --git a/src/config-schema.coffee b/src/config-schema.coffee index ed6691380..c113f53db 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -197,7 +197,7 @@ module.exports = softWrapAtPreferredLineLength: type: 'boolean' default: false - description: 'Instead of wrapping lines to the window\'s width, wrap lines to the number of characters defined by the `Preferred Line Length` setting. This will only take effect when the soft wrap config setting is enabled globally or for the current language.' + description: 'Instead of wrapping lines to the window\'s width, wrap lines to the number of characters defined by the `Preferred Line Length` setting. This will only take effect when the soft wrap config setting is enabled globally or for the current language. **Note:** If you want to hide the wrap guide (the vertical line) you can disable the `wrap-guide` package.' softWrapHangingIndent: type: 'integer' default: 0 diff --git a/src/config.coffee b/src/config.coffee index 66f07516e..290d0ca09 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -785,7 +785,7 @@ class Config properties[key] ?= {} rootSchema = properties[key] - _.extend rootSchema, schema + Object.assign rootSchema, schema @setDefaults(keyPath, @extractDefaultsFromSchema(schema)) @setScopedDefaultsFromSchema(keyPath, schema) @resetSettingsForSchemaChange() @@ -870,7 +870,7 @@ class Config return if @shouldNotAccessFileSystem() allSettings = {'*': @settings} - allSettings = _.extend allSettings, @scopedSettingsStore.propertiesForSource(@getUserConfigPath()) + allSettings = Object.assign allSettings, @scopedSettingsStore.propertiesForSource(@getUserConfigPath()) allSettings = sortObject(allSettings) try CSON.writeFileSync(@configFilePath, allSettings) diff --git a/src/cursor.coffee b/src/cursor.coffee index b8f7c72b4..e2eaa8c05 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -537,8 +537,8 @@ class Cursor extends Model # * `wordRegex` A {RegExp} indicating what constitutes a "word" # (default: {::wordRegExp}). getCurrentWordBufferRange: (options={}) -> - startOptions = _.extend(_.clone(options), allowPrevious: false) - endOptions = _.extend(_.clone(options), allowNext: false) + startOptions = Object.assign(_.clone(options), allowPrevious: false) + endOptions = Object.assign(_.clone(options), allowNext: false) new Range(@getBeginningOfCurrentWordBufferPosition(startOptions), @getEndOfCurrentWordBufferPosition(endOptions)) # Public: Returns the buffer Range for the current line. diff --git a/src/git-repository.coffee b/src/git-repository.coffee index fcbc40830..fceb4850a 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -318,7 +318,7 @@ class GitRepository getDirectoryStatus: (directoryPath) -> directoryPath = "#{@relativize(directoryPath)}/" directoryStatus = 0 - for path, status of _.extend({}, @async.getCachedPathStatuses(), @statusesByPath) + for path, status of Object.assign({}, @async.getCachedPathStatuses(), @statusesByPath) directoryStatus |= status if path.indexOf(directoryPath) is 0 directoryStatus diff --git a/src/scan-handler.coffee b/src/scan-handler.coffee index 6199c1fb1..18e00dedc 100644 --- a/src/scan-handler.coffee +++ b/src/scan-handler.coffee @@ -1,4 +1,3 @@ -_ = require "underscore-plus" path = require "path" async = require "async" {PathSearcher, PathScanner, search} = require 'scandal' @@ -26,7 +25,7 @@ module.exports = (rootPaths, regexSource, options) -> async.each( rootPaths, (rootPath, next) -> - options2 = _.extend {}, options, + options2 = Object.assign {}, options, inclusions: processPaths(rootPath, options.inclusions) globalExclusions: processPaths(rootPath, options.globalExclusions) diff --git a/src/selection.coffee b/src/selection.coffee index 7ecbb3fbc..8e9bf827e 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -1,5 +1,5 @@ {Point, Range} = require 'text-buffer' -{pick} = _ = require 'underscore-plus' +{pick} = require 'underscore-plus' {Emitter} = require 'event-kit' Model = require './model' @@ -738,7 +738,7 @@ class Selection extends Model else options.goalScreenRange = myGoalScreenRange ? otherGoalScreenRange - @setBufferRange(@getBufferRange().union(otherSelection.getBufferRange()), _.extend(autoscroll: false, options)) + @setBufferRange(@getBufferRange().union(otherSelection.getBufferRange()), Object.assign(autoscroll: false, options)) otherSelection.destroy() ### diff --git a/src/text-editor.coffee b/src/text-editor.coffee index e054a3e33..afbddd46e 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -2596,7 +2596,7 @@ class TextEditor extends Model # Returns the new {Selection}. addSelection: (marker, options={}) -> cursor = @addCursor(marker) - selection = new Selection(_.extend({editor: this, marker, cursor, @clipboard}, options)) + selection = new Selection(Object.assign({editor: this, marker, cursor, @clipboard}, options)) @selections.push(selection) selectionBufferRange = selection.getBufferRange() @mergeIntersectingSelections(preserveFolds: options.preserveFolds) diff --git a/src/workspace.coffee b/src/workspace.coffee index 5e9de93dd..faa7b84c9 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -549,7 +549,7 @@ class Workspace extends Model throw error @project.bufferForPath(filePath, options).then (buffer) => - editor = @buildTextEditor(_.extend({buffer, largeFileMode}, options)) + editor = @buildTextEditor(Object.assign({buffer, largeFileMode}, options)) disposable = atom.textEditors.add(editor) grammarSubscription = editor.observeGrammar(@handleGrammarUsed.bind(this)) editor.onDidDestroy -> @@ -572,7 +572,7 @@ class Workspace extends Model # # Returns a {TextEditor}. buildTextEditor: (params) -> - params = _.extend({ + params = Object.assign({ @config, @clipboard, @grammarRegistry, @assert }, params) new TextEditor(params)