Skip to content

Instantly share code, notes, and snippets.

@Kreozot
Created August 26, 2015 06:09
Show Gist options
  • Save Kreozot/46f58d9f9cf2a08b7fd8 to your computer and use it in GitHub Desktop.
Save Kreozot/46f58d9f9cf2a08b7fd8 to your computer and use it in GitHub Desktop.
/**
* Создание бэкапа Битрикса
*
* Требуется файл secret.json, в котором будут храниться данные пользователя Битрикса и URL локального проекта:
* {
* "bitrix": {
* "username": "v.pupkin",
* "password": "mySecretPassword"
* },
* "localUrl": "http://mysite.local/"
* }
* Кроме того подразумевается, что у вас уже поднят локальный сервер, адрес которого прописан в localUrl (secret.json), а корень находится в папке c текущим скриптом
*/
var Nightmare = require('nightmare'),
config = require('./package.json').config,
secret = require('./secret.json'),
http = require('http'),
fs = require('fs'),
Q = require('q'),
ProgressBar = require('progress');
var bitrixUrl = config.urls.dev.replace('.com', '.int') + 'bitrix/';
var dbConfig;
function makeBackup() {
return Q.Promise(function (resolve, reject, notify) {
var backupLink,
restoreUrl;
new Nightmare({
timeout: 240000
})
.goto(bitrixUrl + 'admin/dump.php?lang=ru')
.type('input.login-input[name="USER_LOGIN"]', secret.bitrix.username)
.type('input.login-input[name="USER_PASSWORD"]', secret.bitrix.password)
.click('input[type="submit"]')
.wait(7000)
.click('#dump_bucket_id_0') // Размещение резервной копии: в папке сайта
.click('#tab_cont_expert') // Параметры
.wait(1000)
.click('#dump_expert') // Включить экспертные настройки создания резервной копии
.type('input[name="dump_archive_size_limit"]', '2047') // Максимальный размер несжатых данных в одной части архива (МБ): 2047
.check('input[name="dump_file_public"]') // Архивировать публичную часть
.check('input[name="skip_mask"]') // Исключить из архива файлы и директории по маске
.click('#start_button') // Создать резервную копию
.wait('.adm-info-message-icon')
.goto(bitrixUrl + 'admin/dump_list.php?lang=ru') // Список резервных копий
.click('div.adm-info-message>a:nth-child(1)') // Ячейка с названием последней резервной копии
// Получить название файла резервной копии
.evaluate(function () {
return '' + document.evaluate(
'//table[@id="tbl_dump"]/tbody/tr[1]/td[3]',
document,
null,
XPathResult.ORDERED_NODE_ITERATOR_TYPE,
null).iterateNext().innerText;
}, function (result) {
backupLink = result;
})
// Скачать restore.php
.evaluate(function () {
var restoreUrl = '' + document.evaluate(
'//div[@class="adm-info-message"]/a',
document,
null,
XPathResult.ORDERED_NODE_ITERATOR_TYPE,
null).iterateNext().href;
var xhr = new XMLHttpRequest();
xhr.open("GET", restoreUrl, false);
xhr.overrideMimeType("text/plain; charset=x-user-defined");
xhr.send();
return xhr.responseText;
}, function (result) {
fs.writeFileSync("restore.php", result, "binary");
console.log('restore.php downloaded');
})
// Файл настроек БД
.goto(bitrixUrl + 'admin/fileman_file_edit.php?path=%2Fbitrix%2Fphp_interface%2Fdbconn.php&full_src=Y&site=s1&lang=ru')
.evaluate(function () {
var settings = '' + document.querySelector('.bxce-highlight').innerText;
var dbConfig = {};
dbConfig.login = settings.match(/\$DBLogin = "([\S]+)";/)[1];
dbConfig.password = settings.match(/\$DBPassword = "([\S]+)";/)[1];
dbConfig.name = settings.match(/\$DBName = "([\S]+)";/)[1];
return dbConfig;
}, function (result) {
dbConfig = result;
dbConfig.host = config.urls.dev
.replace('.com', '.int')
.replace('http://', '')
.replace('/', '');
})
.run(function (err, nightmare) {
if (err) {
reject(err);
} else {
console.log('Backup saved in bitrix as ' + backupLink);
resolve(backupLink);
};
});
});
}
function downloadBackup(filename) {
return Q.Promise(function (resolve, reject, notify) {
var backupUrl = bitrixUrl + 'backup/' + filename;
var file = fs.createWriteStream(filename);
var req = http.get(backupUrl, function (res) {
var len = parseInt(res.headers['content-length'], 10);
console.log();
var bar = new ProgressBar(' downloading [:bar] :percent :etas', {
complete: '=',
incomplete: ' ',
width: 30,
total: len
});
res.on('data', function (chunk) {
bar.tick(chunk.length);
});
res.on('end', function () {
console.log('\n');
resolve(filename);
});
res.pipe(file);
})
.on('error', function (err) {
reject(err);
});
});
}
function restoreBackup(filename) {
return Q.Promise(function (resolve, reject, notify) {
nightmare = new Nightmare({
timeout: 240000
});
var skip = false;
nightmare
.goto(secret.localUrl + 'restore.php?lang=ru')
.click('input[value="Далее"]') // Далее
.wait(2000)
.click('input[onclick="div_show(3)"]') // Архив загружен в корневую папку сервера
.select('select[name="arc_name"]', filename)
.click('input[value="Далее"]') // Далее
.on('loadFinished', function (status) {
if (!skip) {
nightmare
.evaluate(function () {
var valueDiv = document.querySelector('div[align="center"]');
if (valueDiv) {
return '' + valueDiv.innerText;
} else {
return false;
}
return value;
}, function (result) {
if (result) {
console.log(result);
}
})
.evaluate(function () {
document.isReloaded = true;
if (document.querySelector('input[value="Пропустить"]')) {
return 'skip';
} else if (document.querySelector('input[name="DBHost"]')) {
return 'db';
} else {
return false;
}
}, function (result) {
if (result == 'skip') {
nightmare
.click('input[value="Пропустить"]')
// Ожидание перезагрузки страницы
.wait(function () {
return !document.isReloaded;
}, true)
// Проверка, существует ли div с процентом выполнения
.evaluate(function () {
var centerDiv = document.querySelector('div[align="center"]');
if (centerDiv) {
document.isReloaded = true;
return true;
} else {
document.isReloaded = true;
return false;
}
}, function (result) {
// Если div не найден, то запускаем ещё одно ожидание перезагрузки
if (!result) {
console.log('complete. moving on...')
nightmare
.wait(function () {
return !document.isReloaded;
}, true);
}
});
} else if (result == 'db') {
console.log('Canceling DB restore');
skip = true;
nightmare
.click('input[value="Пропустить восстановление базы"]')
.wait(2000);
} else {
nightmare
// Ожидание перезагрузки страницы
.wait(function () {
return !document.isReloaded;
}, true)
// Проверка, существует ли форма с данными БД
.evaluate(function () {
var hostInput = document.querySelector('input[name="DBHost"]');
if (hostInput) {
document.isReloaded = true;
return true;
} else {
document.isReloaded = true;
return false;
}
}, function (result) {
// Если не существует, запускаем ещё одно ожидание
if (!result) {
nightmare
.wait(function () {
return !document.isReloaded;
}, true);
}
});
}
});
}
})
.wait(5000)
.run(function (err, nightmare) {
if (err) {
reject(err);
} else {
console.log('Backup restored');
resolve(true);
};
});
});
}
function writeDBConfigInSettings() {
return Q.Promise(function (resolve, reject, notify) {
console.log('Writing DB config in .settings.php');
var filepath = './bitrix/.settings.php';
fs.readFile(filepath, 'utf8', function(err, data) {
if (err) {
reject(err);
}
var result = data
.replace(/'host' => '[\S]+'/, "'host' => '" + dbConfig.host + "'")
.replace(/'database' => '[\S]+'/, "'database' => '" + dbConfig.name + "'")
.replace(/'login' => '[\S]+'/, "'login' => '" + dbConfig.login + "'")
.replace(/'password' => '[\S]+'/, "'password' => '" + dbConfig.password + "'");
fs.writeFile(filepath, result, 'utf8', function(err) {
if (err) {
reject(err);
} else {
console.log('Done');
resolve(true);
}
});
});
});
}
function writeDBConfigInDBConn() {
return Q.Promise(function (resolve, reject, notify) {
console.log('Writing DB config in php_interface/dbconn.php');
var filepath = './bitrix/php_interface/dbconn.php';
fs.readFile(filepath, 'utf8', function(err, data) {
if (err) {
reject(err);
}
var result = data
.replace(/\$DBHost = "[\S]+"/, '$DBHost = "' + dbConfig.host + '"')
.replace(/\$DBLogin = "[\S]+"/, '$DBLogin = "' + dbConfig.login + '"')
.replace(/\$DBPassword = "[\S]+"/, '$DBPassword = "' + dbConfig.password + '"')
.replace(/\$DBName = "[\S]+"/, '$DBName = "' + dbConfig.name + '"');
fs.writeFile(filepath, result, 'utf8', function(err) {
if (err) {
reject(err);
} else {
console.log('Done');
resolve(true);
}
});
});
});
}
makeBackup()
.then(function (backupFilename) {
return downloadBackup(backupFilename);
})
.then(function (backupFilename) {
return restoreBackup(backupFilename)
})
.then(function() {
writeDBConfigInSettings();
})
.then(function() {
writeDBConfigInDBConn();
})
.catch(function (error) {
console.log('Error: ' + error);
})
.done();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment