/
install.js
176 lines (152 loc) · 6.01 KB
/
install.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
'use strict';
const path = require('path');
const Command = require('../command');
const symlinkSync = require('symlink-or-copy').sync;
const SetupCommand = require('./setup');
const DoctorCommand = require('./doctor');
class InstallCommand extends Command {
static configureOptions(commandName, yargs, extensions) {
yargs = super.configureOptions(commandName, yargs, extensions);
yargs = SetupCommand.configureOptions('setup', yargs, extensions, true);
return yargs;
}
run(argv) {
const errors = require('../errors');
const yarnInstall = require('../tasks/yarn-install');
const dirIsEmpty = require('../utils/dir-is-empty');
const ensureStructure = require('../tasks/ensure-structure');
let version = argv.version;
// Check if the directory is empty
if (!dirIsEmpty(process.cwd())) {
return Promise.reject(new errors.SystemError('Current directory is not empty, Ghost cannot be installed here.'));
}
let local = false;
// If command is `ghost install local`, or command is
// `ghost install 1.x.x --local`, do a local install
if (version === 'local' || argv.local || (argv._ && argv._.includes('local'))) {
local = true;
version = (version === 'local') ? null : version;
this.system.setEnvironment(true, true);
}
return this.runCommand(DoctorCommand, Object.assign({
categories: ['install'],
skipInstanceCheck: true,
quiet: true
}, argv, {local})).then(() => this.ui.listr([{
title: 'Checking for latest Ghost version',
task: this.version
}, {
title: 'Setting up install directory',
task: ensureStructure
}, {
title: 'Downloading and installing Ghost',
task: (ctx, task) => {
task.title = `Downloading and installing Ghost v${ctx.version}`;
return yarnInstall(ctx.ui, ctx.argv.zip);
}
}, {
title: 'Finishing install process',
task: () => this.ui.listr([{
title: 'Linking latest Ghost and recording versions',
task: this.link.bind(this)
}, {
title: 'Linking latest Casper',
task: this.casper
}], false)
}], {
argv: {...argv, version},
cliVersion: this.system.cliVersion
})).then(() => {
if (!argv.setup) {
return Promise.resolve();
}
argv.local = local;
return this.runCommand(SetupCommand, argv);
});
}
async version(ctx) {
const semver = require('semver');
const {SystemError} = require('../errors');
const {resolveVersion, versionFromZip} = require('../utils/version');
let {version, zip, v1, fromExport} = ctx.argv;
let exportVersion = null;
if (fromExport) {
const {parseExport} = require('../tasks/import');
const parsed = parseExport(fromExport);
exportVersion = parsed.version;
if (semver.major(exportVersion) === 0) {
ctx.ui.log('Detected a v0.x export file. Installing latest v1.x version.', 'green');
version = 'v1';
} else if (!version) {
version = exportVersion;
}
}
if (version && zip) {
ctx.ui.log('Warning: you specified both a specific version and a zip file. The version in the zip file will be used.', 'yellow');
}
let resolvedVersion = null;
if (zip) {
resolvedVersion = await versionFromZip(zip);
} else {
resolvedVersion = await resolveVersion(version, null, {v1});
}
if (exportVersion && semver.lt(resolvedVersion, exportVersion)) {
throw new SystemError(`Cannot import an export from v${exportVersion} into v${resolvedVersion} of Ghost.`);
}
ctx.version = resolvedVersion; // eslint-disable-line require-atomic-updates
ctx.installPath = path.join(process.cwd(), 'versions', resolvedVersion); // eslint-disable-line require-atomic-updates
}
casper() {
// Create a symlink to the theme from the current version
return symlinkSync(
path.join(process.cwd(), 'current', 'content', 'themes', 'casper'),
path.join(process.cwd(), 'content', 'themes', 'casper')
);
}
link(ctx) {
symlinkSync(ctx.installPath, path.join(process.cwd(), 'current'));
const instance = this.system.getInstance();
instance.version = ctx.version;
instance.cliVersion = this.system.cliVersion;
}
}
InstallCommand.global = true;
InstallCommand.description = 'Install a brand new instance of Ghost';
InstallCommand.longDescription = '$0 install [version|local]\n Installs a new version of Ghost. Run `ghost install local` to install for local theme development/testing';
InstallCommand.params = '[version]';
InstallCommand.options = {
// This overrides the description of the global option for this command
dir: {
alias: 'd',
description: 'Folder to install Ghost in',
type: 'string'
},
zip: {
description: 'Path to Ghost release zip to install',
type: 'string'
},
version1: {
alias: 'v1',
describe: 'Limit install to Ghost 1.x releases',
type: 'boolean',
default: false
},
stack: {
description: '[--no-stack] Enable/Disable system stack checks on install',
type: 'boolean',
default: true
},
setup: {
description: '[--no-setup] Enable/Disable auto-running the setup command',
type: 'boolean',
default: true
},
'from-export': {
alias: 'f',
description: 'Path to a Ghost export file to import after setup',
type: 'string'
}
};
InstallCommand.runPreChecks = true;
InstallCommand.ensureDir = true;
module.exports = InstallCommand;