pulsar/script/lib/install-application.js
2018-01-13 01:53:19 +01:00

158 lines
6.6 KiB
JavaScript

'use strict'
const fs = require('fs-extra')
const handleTilde = require('./handle-tilde')
const path = require('path')
const template = require('lodash.template')
const startCase = require('lodash.startcase')
const execSync = require('child_process').execSync
const CONFIG = require('../config')
function install (installationDirPath, packagedAppFileName, packagedAppPath) {
if (fs.existsSync(installationDirPath)) {
console.log(`Removing previously installed "${packagedAppFileName}" at "${installationDirPath}"`)
fs.removeSync(installationDirPath)
}
console.log(`Installing "${packagedAppFileName}" at "${installationDirPath}"`)
fs.copySync(packagedAppPath, installationDirPath)
}
/**
* Finds the path to the base directory of the icon default icon theme
* This follows the freedesktop Icon Theme Specification:
* https://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html#install_icons
* and the XDG Base Directory Specification:
* https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables
*/
function findBaseIconThemeDirPath () {
const defaultBaseIconThemeDir = '/usr/share/icons/hicolor'
const dataDirsString = process.env.XDG_DATA_DIRS
if (dataDirsString) {
const dataDirs = dataDirsString.split(path.delimiter)
if (dataDirs.includes('/usr/share/') || dataDirs.includes('/usr/share')) {
return defaultBaseIconThemeDir
} else {
return path.join(dataDirs[0], 'icons', 'hicolor')
}
} else {
return defaultBaseIconThemeDir
}
}
module.exports = function (packagedAppPath, installDir) {
const packagedAppFileName = path.basename(packagedAppPath)
if (process.platform === 'darwin') {
const installPrefix = installDir !== '' ? handleTilde(installDir) : path.join(path.sep, 'Applications')
const installationDirPath = path.join(installPrefix, packagedAppFileName)
install(installationDirPath, packagedAppFileName, packagedAppPath)
} else if (process.platform === 'win32') {
const installPrefix = installDir !== '' ? installDir : process.env.LOCALAPPDATA
const installationDirPath = path.join(installPrefix, packagedAppFileName, 'app-dev')
try {
install(installationDirPath, packagedAppFileName, packagedAppPath)
} catch (e) {
console.log(`Administrator elevation required to install into "${installationDirPath}"`)
const fsAdmin = require('fs-admin')
return new Promise((resolve, reject) => {
fsAdmin.recursiveCopy(packagedAppPath, installationDirPath, (error) => {
error ? reject(error) : resolve()
})
})
}
} else {
const atomExecutableName = CONFIG.channel === 'stable' ? 'atom' : 'atom-' + CONFIG.channel
const apmExecutableName = CONFIG.channel === 'stable' ? 'apm' : 'apm-' + CONFIG.channel
const appName = CONFIG.channel === 'stable' ? 'Atom' : startCase('Atom ' + CONFIG.channel)
const appDescription = CONFIG.appMetadata.description
const prefixDirPath = installDir !== '' ? handleTilde(installDir) : path.join('/usr', 'local')
const shareDirPath = path.join(prefixDirPath, 'share')
const installationDirPath = path.join(shareDirPath, atomExecutableName)
const applicationsDirPath = path.join(shareDirPath, 'applications')
const binDirPath = path.join(prefixDirPath, 'bin')
fs.mkdirpSync(applicationsDirPath)
fs.mkdirpSync(binDirPath)
install(installationDirPath, packagedAppFileName, packagedAppPath)
{ // Install icons
const baseIconThemeDirPath = findBaseIconThemeDirPath()
const fullIconName = atomExecutableName + '.png'
let existingIconsFound = false
fs.readdirSync(baseIconThemeDirPath).forEach(size => {
const iconPath = path.join(baseIconThemeDirPath, size, 'apps', fullIconName)
if (fs.existsSync(iconPath)) {
if (!existingIconsFound) {
console.log(`Removing existing icons from "${baseIconThemeDirPath}"`)
}
existingIconsFound = true
fs.removeSync(iconPath)
}
})
console.log(`Installing icons at "${baseIconThemeDirPath}"`)
const appIconsPath = path.join(CONFIG.repositoryRootPath, 'resources', 'app-icons', CONFIG.channel, 'png')
fs.readdirSync(appIconsPath).forEach(imageName => {
if (/\.png$/.test(imageName)) {
const size = path.basename(imageName, '.png')
const iconPath = path.join(appIconsPath, imageName)
fs.copySync(iconPath, path.join(baseIconThemeDirPath, `${size}x${size}`, 'apps', fullIconName))
}
})
console.log(`Updating icon cache for "${baseIconThemeDirPath}"`)
try {
execSync(`gtk-update-icon-cache ${baseIconThemeDirPath} --force`)
} catch (e) {}
}
{ // Install xdg desktop file
const desktopEntryPath = path.join(applicationsDirPath, `${atomExecutableName}.desktop`)
if (fs.existsSync(desktopEntryPath)) {
console.log(`Removing existing desktop entry file at "${desktopEntryPath}"`)
fs.removeSync(desktopEntryPath)
}
console.log(`Writing desktop entry file at "${desktopEntryPath}"`)
const desktopEntryTemplate = fs.readFileSync(path.join(CONFIG.repositoryRootPath, 'resources', 'linux', 'atom.desktop.in'))
const desktopEntryContents = template(desktopEntryTemplate)({
appName,
appFileName: atomExecutableName,
description: appDescription,
installDir: prefixDirPath,
iconPath: atomExecutableName
})
fs.writeFileSync(desktopEntryPath, desktopEntryContents)
}
{ // Add atom executable to the PATH
const atomBinDestinationPath = path.join(binDirPath, atomExecutableName)
if (fs.existsSync(atomBinDestinationPath)) {
console.log(`Removing existing executable at "${atomBinDestinationPath}"`)
fs.removeSync(atomBinDestinationPath)
}
console.log(`Copying atom.sh to "${atomBinDestinationPath}"`)
fs.copySync(path.join(CONFIG.repositoryRootPath, 'atom.sh'), atomBinDestinationPath)
}
{ // Link apm executable to the PATH
const apmBinDestinationPath = path.join(binDirPath, apmExecutableName)
try {
fs.lstatSync(apmBinDestinationPath)
console.log(`Removing existing executable at "${apmBinDestinationPath}"`)
fs.removeSync(apmBinDestinationPath)
} catch (e) { }
console.log(`Symlinking apm to "${apmBinDestinationPath}"`)
fs.symlinkSync(path.join('..', 'share', atomExecutableName, 'resources', 'app', 'apm', 'node_modules', '.bin', 'apm'), apmBinDestinationPath)
}
console.log(`Changing permissions to 755 for "${installationDirPath}"`)
fs.chmodSync(installationDirPath, '755')
}
return Promise.resolve()
}