diff --git a/spec/atom-portable-spec.coffee b/spec/atom-portable-spec.coffee new file mode 100644 index 000000000..4665621ff --- /dev/null +++ b/spec/atom-portable-spec.coffee @@ -0,0 +1,49 @@ +path = require "path" +fs = require 'fs-plus' +temp = require "temp" +rimraf = require "rimraf" +AtomPortable = require "../src/browser/atom-portable" + +describe "Check for Portable Mode", -> + describe "Windows", -> + describe "with ATOM_HOME environment variable", -> + it "returns false", -> + expect(AtomPortable.isPortableInstall("win32", "C:\\some\\path")).toBe false + + describe "without ATOM_HOME environment variable", -> + environmentAtomHome = undefined + portableAtomHomePath = path.join(path.dirname(process.execPath), "..", ".atom") + portableAtomHomeNaturallyExists = fs.existsSync(portableAtomHomePath) + portableAtomHomeBackupPath = "#{portableAtomHomePath}.temp" + + beforeEach -> + fs.renameSync(portableAtomHomePath, portableAtomHomeBackupPath) if fs.existsSync(portableAtomHomePath) + + afterEach -> + if portableAtomHomeNaturallyExists + fs.renameSync(portableAtomHomeBackupPath, portableAtomHomePath) if not fs.existsSync(portableAtomHomePath) + else + rimraf.sync(portableAtomHomePath) if fs.existsSync(portableAtomHomePath) + rimraf.sync(portableAtomHomeBackupPath) if fs.existsSync(portableAtomHomeBackupPath) + + describe "with .atom directory sibling to exec", -> + beforeEach -> + fs.mkdirSync(portableAtomHomePath) if not fs.existsSync(portableAtomHomePath) + + it "returns true", -> + expect(AtomPortable.isPortableInstall("win32", environmentAtomHome)).toBe true + + describe "without .atom directory sibling to exec", -> + beforeEach -> + rimraf.sync(portableAtomHomePath) if fs.existsSync(portableAtomHomePath) + + it "returns false", -> + expect(AtomPortable.isPortableInstall("win32", environmentAtomHome)).toBe false + + describe "Mac", -> + it "returns false", -> + expect(AtomPortable.isPortableInstall("darwin", "darwin")).toBe false + + describe "Linux", -> + it "returns false", -> + expect(AtomPortable.isPortableInstall("linux", "linux")).toBe false diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 2619d5773..f98e1b835 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -1,5 +1,6 @@ crypto = require 'crypto' path = require 'path' +ipc = require 'ipc' _ = require 'underscore-plus' {deprecate} = require 'grim' @@ -203,6 +204,15 @@ class AtomEnvironment extends Model @observeAutoHideMenuBar() + checkPortableHomeWritable = -> + responseChannel = "check-portable-home-writable-response" + ipc.on responseChannel, (response) -> + ipc.removeAllListeners(responseChannel) + atom.notifications.addWarning("#{response.message.replace(/([\\\.+\\-_#!])/g, '\\$1')}") if not response.writable + ipc.send('check-portable-home-writable', responseChannel) + + checkPortableHomeWritable() + setConfigSchema: -> @config.setSchema null, {type: 'object', properties: _.clone(require('./config-schema'))} diff --git a/src/browser/atom-portable.coffee b/src/browser/atom-portable.coffee new file mode 100644 index 000000000..a8cbd2d41 --- /dev/null +++ b/src/browser/atom-portable.coffee @@ -0,0 +1,32 @@ +fs = require 'fs-plus' +path = require 'path' +ipc = require 'ipc' + +module.exports = +class AtomPortable + @getPortableAtomHomePath: -> + execDirectoryPath = path.dirname(process.execPath) + path.join(execDirectoryPath, '..', '.atom') + + @isPortableInstall: (platform, environmentAtomHome, defaultHome) -> + return false unless platform is 'win32' + return false if environmentAtomHome + return false if not fs.existsSync(@getPortableAtomHomePath()) + # currently checking only that the directory exists and is writable, + # probably want to do some integrity checks on contents in future + @isPortableAtomHomePathWritable(defaultHome) + + @isPortableAtomHomePathWritable: (defaultHome) -> + writable = false + message = "" + try + writePermissionTestFile = path.join(@getPortableAtomHomePath(), "write.test") + fs.writeFileSync(writePermissionTestFile, "test") if not fs.existsSync(writePermissionTestFile) + fs.removeSync(writePermissionTestFile) + writable = true + catch error + message = "Failed to use portable Atom home directory (#{@getPortableAtomHomePath()}). Using the default instead (#{defaultHome}). #{error.message}" + + ipc.on 'check-portable-home-writable', (event) -> + event.sender.send 'check-portable-home-writable-response', {writable, message} + writable diff --git a/src/browser/main.coffee b/src/browser/main.coffee index 990002671..48485486b 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -60,6 +60,8 @@ setupCrashReporter = -> setupAtomHome = -> return if process.env.ATOM_HOME atomHome = path.join(app.getHomeDir(), '.atom') + AtomPortable = require './atom-portable' + atomHome = AtomPortable.getPortableAtomHomePath() if AtomPortable.isPortableInstall(process.platform, process.env.ATOM_HOME, atomHome) try atomHome = fs.realpathSync(atomHome) process.env.ATOM_HOME = atomHome diff --git a/static/index.js b/static/index.js index 72a974242..c21cd6327 100644 --- a/static/index.js +++ b/static/index.js @@ -17,6 +17,8 @@ }) // Ensure ATOM_HOME is always set before anything else is required + // This is because of a difference in Linux not inherited between browser and render processes + // issue #5142 setupAtomHome() blobStore = FileSystemBlobStore.load(