libs/theme_manager/theme_manager.js
// * ———————————————————————————————————————————————————————— * //
// * theme manager
// * downloads a theme and extracts it into a new folder
// * ———————————————————————————————————————————————————————— * //
const theme_manager = function () {}
// * vendor dependencies
const Promise = require('bluebird')
const request = require('request-promise')
const zlib = require('zlib')
const tar = require('tar')
const inquirer = require('inquirer')
const fs = Promise.promisifyAll(require('fs-extra'))
const npm = require('npm')
const opn = require('opn')
const _ = require('lodash')
const path = require('path')
// * enduro dependencies
const flat_helpers = require(enduro.enduro_path + '/libs/flat_db/flat_helpers')
const flat = require(enduro.enduro_path + '/libs/flat_db/flat')
const logger = require(enduro.enduro_path + '/libs/logger')
const admin_security = require(enduro.enduro_path + '/libs/admin_utilities/admin_security')
const format_service = require(enduro.enduro_path + '/libs/services/format_service')
const enduro_instance = require(enduro.enduro_path + '/index').quick_init()
const theme_manager_api_routes = {
get_theme_by_name: 'http://www.endurojs.com/theme_manager/get_theme_by_name',
get_all_themes: 'http://www.endurojs.com/theme_manager/get_all_themes',
}
// Goes through the pages and renders them
theme_manager.prototype.create_from_theme = function (theme_name) {
const self = this
logger.init('Enduro theme service')
// will store variables for the promise chain
let theme_progress_variables = {}
// get info for the specified theme
return self.fetch_theme_info_by_name(theme_name)
// promnt user to input settings for the project
.then((theme_info) => {
// store the theme info
theme_progress_variables.theme_info = theme_info
return inquirer.prompt([
{
name: 'project_name',
message: 'choose project name:',
type: 'input'
},
{
name: 'login_username',
message: 'choose your admin login:',
type: 'input'
},
{
name: 'login_password',
message: 'choose your admin password:',
type: 'password'
},
])
}, theme_error)
// create directory with specified name
.then(function (answers) {
// stores the answers
theme_progress_variables.answers = answers
theme_progress_variables.answers.project_name = format_service.enduro_slug(theme_progress_variables.answers.project_name)
return flat_helpers.ensure_directory_existence(process.cwd() + '/' + theme_progress_variables.answers.project_name + '/.')
}, theme_error)
// get the theme and put it in created folder
.then(function () {
return self.download_and_extract_theme_by_gz_link(theme_progress_variables.theme_info.gz_link, theme_progress_variables.answers.project_name)
}, theme_error)
.then(() => {
return self.clean_fresh_theme()
}, theme_error)
.then(() => {
logger.loading('starting enduro')
logger.silent()
return enduro_instance.init({ project_path: path.join(process.cwd(), theme_progress_variables.answers.project_name) })
}, theme_error)
// sets up admin credentials
.then(() => {
logger.noisy()
logger.loaded()
logger.twolog('setting up admin credentials', '✓')
logger.silent()
return admin_security.add_admin(theme_progress_variables.answers.login_username, theme_progress_variables.answers.login_password)
}, theme_error)
// reads project dependencies
.then(() => {
logger.noisy()
logger.twolog('getting project dependencies', '✓')
return fs.readJsonAsync('./' + theme_progress_variables.answers.project_name + '/package.json')
}, theme_error)
.then((fetched_package) => {
logger.loading('installing npm dependencies')
logger.silent()
return new Promise(function (resolve, reject) {
// workaround to make npm silent
const log_temp = console.log
console.log = function () {}
npm.load({
loaded: false,
progress: false,
loglevel: 'error',
}, () => {
// we get all npm dependencies, but to, speed up, remove enduro, since it's
// probably already installed globally
const npm_dependencies = _.chain(fetched_package.dependencies)
.omit('enduro')
.toPairs()
.map((dependency) => {
return dependency[0] + '@' + dependency[1]
})
.value()
npm.commands.install(theme_progress_variables.answers.project_name, npm_dependencies, function (err, data) {
if (err) { console.log(err) }
// trick npm into believeing it's in the theme's folder
npm.localPrefix = path.join(process.cwd(), theme_progress_variables.answers.project_name)
// run postinstall script
npm.commands.run(['postinstall'], function (err) {
if (err) { console.log(err) }
// no need to silence npm, enable console.log
console.log = log_temp
logger.loaded()
resolve()
})
})
})
})
}, theme_error)
.then(() => {
logger.noisy()
logger.loaded()
return enduro.actions.start()
}, theme_error)
.then(() => {
logger.loaded()
logger.line()
logger.log('')
logger.log('your project was created successfully', true)
logger.log('to start your project again, just cd')
logger.log('into project directory and run', true)
logger.tablog('$ enduro dev', true)
logger.loading('the browser should open soon')
// open localhost in 3 seconds
// the delay is there to make the process more calm
setTimeout(() => {
logger.loaded()
logger.end()
opn('http://localhost:5000/')
}, 3000)
}, theme_error)
.then(null, () => {})
}
// * ———————————————————————————————————————————————————————— * //
// * get all themes
// *
// * fetches list of themes
// * @return {array} - list of all available themes
// * ———————————————————————————————————————————————————————— * //
theme_manager.prototype.get_all_themes = function () {
return request(theme_manager_api_routes.get_all_themes)
.then((all_themes_as_string) => {
return JSON.parse(all_themes_as_string)
})
}
// * ———————————————————————————————————————————————————————— * //
// * fetch theme by name
// *
// * requests theme by theme name
// * @param {string} theme_name
// * @return {Promise} - promise with theme info as context
// * ———————————————————————————————————————————————————————— * //
theme_manager.prototype.fetch_theme_info_by_name = function (theme_name, options) {
const self = this
// list all themes and exit if specified theme is not found
if (!theme_name) {
return self.get_all_themes()
.then((all_themes) => {
return inquirer.prompt([
{
name: 'theme_name',
message: 'choose a theme',
type: 'list',
default: 'mirror',
choices: all_themes.map((theme) => { return theme.name }),
},
])
})
.then((theme) => {
return self.fetch_theme_info_by_name(theme.theme_name)
})
}
logger.loading('getting info for \'' + theme_name + '\' theme')
return request({
url: theme_manager_api_routes.get_theme_by_name + '/' + theme_name,
qs: options,
})
.then((themes_response) => {
themes_response = JSON.parse(themes_response)
logger.loaded()
if (!themes_response.found) {
logger.log('theme not found')
logger.end()
return Promise.reject()
}
return themes_response.theme_info
})
}
// * ———————————————————————————————————————————————————————— * //
// * download and extract theme by gzip link
// *
// * @param {string} gz_link - remote link hosting the gzip archive
// * @param {string} project_name - project_name will serve as folder for the new project relative to current path
// * @return {Promise} - empty promise
// * ———————————————————————————————————————————————————————— * //
theme_manager.prototype.download_and_extract_theme_by_gz_link = function (gz_link, project_name) {
logger.loading('downloading and extracting theme')
global.enduro.project_path = enduro.project_path || process.cwd()
const extract_destination = path.join(enduro.project_path, project_name)
return flat_helpers.ensure_directory_existence(path.join(extract_destination, 'fake.txt'))
.then(() => {
return new Promise(function (resolve, reject) {
// downloads and extracts
request(gz_link)
.pipe(tar.extract({
cwd: path.join(enduro.project_path, project_name),
strip: 1,
strict: 1,
}))
.on('close', function () {
logger.loaded()
global.enduro.project_path = path.join(enduro.project_path, project_name)
resolve()
})
})
})
}
// * ———————————————————————————————————————————————————————— * //
// * list themes
// *
// * prints out supplied themes
// * @param {object} themes
// * @return {nothing}
// * ———————————————————————————————————————————————————————— * //
theme_manager.prototype.list_themes = function (themes) {
logger.init('found themes')
logger.log('choose from themes below')
_.forEach(themes, (theme, theme_name) => {
logger.line()
logger.twolog(theme_name)
logger.log(theme.description)
})
logger.end()
}
// * ———————————————————————————————————————————————————————— * //
// * removes theme specific attibutes such as login message
// * and demo users from theme
// *
// * @return {promise} - empty promise
// * ———————————————————————————————————————————————————————— * //
theme_manager.prototype.clean_fresh_theme = function () {
return flat.upsert('.settings', { settings: { login_message: '' }})
.then(() => {
return admin_security.remove_all_users()
})
}
// helper function that propagates error in the promise chain
function theme_error (n) {
throw (n)
}
module.exports = new theme_manager()