/ script / lib / create-debian-package.js
create-debian-package.js
  1  'use strict';
  2  
  3  const fs = require('fs-extra');
  4  const os = require('os');
  5  const path = require('path');
  6  const spawnSync = require('./spawn-sync');
  7  const template = require('lodash.template');
  8  
  9  const CONFIG = require('../config');
 10  
 11  module.exports = function(packagedAppPath) {
 12    console.log(`Creating Debian package for "${packagedAppPath}"`);
 13    const atomExecutableName =
 14      CONFIG.channel === 'stable' ? 'atom' : `atom-${CONFIG.channel}`;
 15    const apmExecutableName =
 16      CONFIG.channel === 'stable' ? 'apm' : `apm-${CONFIG.channel}`;
 17    const appDescription = CONFIG.appMetadata.description;
 18    const appVersion = CONFIG.appMetadata.version;
 19    let arch;
 20    if (process.arch === 'ia32') {
 21      arch = 'i386';
 22    } else if (process.arch === 'x64') {
 23      arch = 'amd64';
 24    } else if (process.arch === 'ppc') {
 25      arch = 'powerpc';
 26    } else {
 27      arch = process.arch;
 28    }
 29  
 30    const outputDebianPackageFilePath = path.join(
 31      CONFIG.buildOutputPath,
 32      `atom-${arch}.deb`
 33    );
 34    const debianPackageDirPath = path.join(
 35      os.tmpdir(),
 36      path.basename(packagedAppPath)
 37    );
 38    const debianPackageConfigPath = path.join(debianPackageDirPath, 'DEBIAN');
 39    const debianPackageInstallDirPath = path.join(debianPackageDirPath, 'usr');
 40    const debianPackageBinDirPath = path.join(debianPackageInstallDirPath, 'bin');
 41    const debianPackageShareDirPath = path.join(
 42      debianPackageInstallDirPath,
 43      'share'
 44    );
 45    const debianPackageAtomDirPath = path.join(
 46      debianPackageShareDirPath,
 47      atomExecutableName
 48    );
 49    const debianPackageApplicationsDirPath = path.join(
 50      debianPackageShareDirPath,
 51      'applications'
 52    );
 53    const debianPackageIconsDirPath = path.join(
 54      debianPackageShareDirPath,
 55      'pixmaps'
 56    );
 57    const debianPackageLintianOverridesDirPath = path.join(
 58      debianPackageShareDirPath,
 59      'lintian',
 60      'overrides'
 61    );
 62    const debianPackageDocsDirPath = path.join(
 63      debianPackageShareDirPath,
 64      'doc',
 65      atomExecutableName
 66    );
 67  
 68    if (fs.existsSync(debianPackageDirPath)) {
 69      console.log(
 70        `Deleting existing build dir for Debian package at "${debianPackageDirPath}"`
 71      );
 72      fs.removeSync(debianPackageDirPath);
 73    }
 74    if (fs.existsSync(`${debianPackageDirPath}.deb`)) {
 75      console.log(
 76        `Deleting existing Debian package at "${debianPackageDirPath}.deb"`
 77      );
 78      fs.removeSync(`${debianPackageDirPath}.deb`);
 79    }
 80    if (fs.existsSync(debianPackageDirPath)) {
 81      console.log(
 82        `Deleting existing Debian package at "${outputDebianPackageFilePath}"`
 83      );
 84      fs.removeSync(debianPackageDirPath);
 85    }
 86  
 87    console.log(
 88      `Creating Debian package directory structure at "${debianPackageDirPath}"`
 89    );
 90    fs.mkdirpSync(debianPackageDirPath);
 91    fs.mkdirpSync(debianPackageConfigPath);
 92    fs.mkdirpSync(debianPackageInstallDirPath);
 93    fs.mkdirpSync(debianPackageShareDirPath);
 94    fs.mkdirpSync(debianPackageApplicationsDirPath);
 95    fs.mkdirpSync(debianPackageIconsDirPath);
 96    fs.mkdirpSync(debianPackageLintianOverridesDirPath);
 97    fs.mkdirpSync(debianPackageDocsDirPath);
 98    fs.mkdirpSync(debianPackageBinDirPath);
 99  
100    console.log(`Copying "${packagedAppPath}" to "${debianPackageAtomDirPath}"`);
101    fs.copySync(packagedAppPath, debianPackageAtomDirPath);
102    fs.chmodSync(debianPackageAtomDirPath, '755');
103  
104    console.log(`Copying binaries into "${debianPackageBinDirPath}"`);
105    fs.copySync(
106      path.join(CONFIG.repositoryRootPath, 'atom.sh'),
107      path.join(debianPackageBinDirPath, atomExecutableName)
108    );
109    fs.symlinkSync(
110      path.join(
111        '..',
112        'share',
113        atomExecutableName,
114        'resources',
115        'app',
116        'apm',
117        'node_modules',
118        '.bin',
119        'apm'
120      ),
121      path.join(debianPackageBinDirPath, apmExecutableName)
122    );
123  
124    console.log(`Writing control file into "${debianPackageConfigPath}"`);
125    const packageSizeInKilobytes = spawnSync('du', ['-sk', packagedAppPath])
126      .stdout.toString()
127      .split(/\s+/)[0];
128    const controlFileTemplate = fs.readFileSync(
129      path.join(
130        CONFIG.repositoryRootPath,
131        'resources',
132        'linux',
133        'debian',
134        'control.in'
135      )
136    );
137    const controlFileContents = template(controlFileTemplate)({
138      appFileName: atomExecutableName,
139      version: appVersion,
140      arch: arch,
141      installedSize: packageSizeInKilobytes,
142      description: appDescription
143    });
144    fs.writeFileSync(
145      path.join(debianPackageConfigPath, 'control'),
146      controlFileContents
147    );
148  
149    console.log(
150      `Writing desktop entry file into "${debianPackageApplicationsDirPath}"`
151    );
152    const desktopEntryTemplate = fs.readFileSync(
153      path.join(
154        CONFIG.repositoryRootPath,
155        'resources',
156        'linux',
157        'atom.desktop.in'
158      )
159    );
160    const desktopEntryContents = template(desktopEntryTemplate)({
161      appName: CONFIG.appName,
162      appFileName: atomExecutableName,
163      description: appDescription,
164      installDir: '/usr',
165      iconPath: atomExecutableName
166    });
167    fs.writeFileSync(
168      path.join(
169        debianPackageApplicationsDirPath,
170        `${atomExecutableName}.desktop`
171      ),
172      desktopEntryContents
173    );
174  
175    console.log(`Copying icon into "${debianPackageIconsDirPath}"`);
176    fs.copySync(
177      path.join(
178        packagedAppPath,
179        'resources',
180        'app.asar.unpacked',
181        'resources',
182        'atom.png'
183      ),
184      path.join(debianPackageIconsDirPath, `${atomExecutableName}.png`)
185    );
186  
187    console.log(`Copying license into "${debianPackageDocsDirPath}"`);
188    fs.copySync(
189      path.join(packagedAppPath, 'resources', 'LICENSE.md'),
190      path.join(debianPackageDocsDirPath, 'copyright')
191    );
192  
193    console.log(
194      `Copying lintian overrides into "${debianPackageLintianOverridesDirPath}"`
195    );
196    fs.copySync(
197      path.join(
198        CONFIG.repositoryRootPath,
199        'resources',
200        'linux',
201        'debian',
202        'lintian-overrides'
203      ),
204      path.join(debianPackageLintianOverridesDirPath, atomExecutableName)
205    );
206  
207    console.log(
208      `Copying polkit configuration into "${debianPackageShareDirPath}"`
209    );
210    fs.copySync(
211      path.join(CONFIG.repositoryRootPath, 'resources', 'linux', 'atom.policy'),
212      path.join(
213        debianPackageShareDirPath,
214        'polkit-1',
215        'actions',
216        `atom-${CONFIG.channel}.policy`
217      )
218    );
219  
220    console.log(`Generating .deb file from ${debianPackageDirPath}`);
221    spawnSync('fakeroot', ['dpkg-deb', '-b', debianPackageDirPath], {
222      stdio: 'inherit'
223    });
224  
225    console.log(
226      `Copying generated package into "${outputDebianPackageFilePath}"`
227    );
228    fs.copySync(`${debianPackageDirPath}.deb`, outputDebianPackageFilePath);
229  };