$engine JScript
$uname extDiffManager
$dname Расширенный diff для попроцедурного сравнения.
$addin global
$addin stdlib
$addin stdcommands
stdlib.require('ScriptForm.js', SelfScript);
stdlib.require('log4js.js', SelfScript);
stdlib.require('SyntaxAnalysis.js', SelfScript);
stdlib.require(stdlib.getSnegopatMainFolder() + 'scripts\\epf\\epfloader.js', SelfScript);
global.connectGlobals(SelfScript)
var logger = Log4js.getLogger(SelfScript.uniqueName);
var appender = new Log4js.BrowserConsoleAppender();
appender.setLayout(new Log4js.PatternLayout(Log4js.PatternLayout.TTCC_CONVERSION_PATTERN));
appenders = [];
appenders.push(appender);
logger.onlog = new Log4js.CustomEvent();
logger.onclear = new Log4js.CustomEvent();
logger.setAppenders(appenders);
logger.setLevel(Log4js.Level.ERROR);
////////////////////////////////////////////////////////////////////////////////////////
////{ Cкрипт extDiffManager (extDiffManager.js) для проекта "Снегопат"
////
//// Описание: Добавляем в процесс объединения стороние инструменты.
//// позволяет сравнивать модули объектов, формы с помощью kdiff , объединять
//// результат сравнения и подгружать обратно в базу изменные.
////
////
//// Автор: Сосна Евгений <shenja@sosna.zp.ua>
////
//// Зробленно в Україні.
////}
////////////////////////////////////////////////////////////////////////////////////////
SelfScript.self['macrosНастройка'] = function() {
var sm = GetCompareWatcher();
sm.show();
return true;
}
SelfScript.self['macrosОбъединитьТекущуюПроцедуру'] = function(){
var sm = GetCompareWatcher();
sm.compareProcedure();
return true;
}
SelfScript.self['macrosОбъединитТекущийОбъект'] = function(){
var sm = GetCompareWatcher();
sm.mergeObject();
return true;
}
SelfScript.self['macrosСравнитьТекущийОбъект'] = function(){
var sm = GetCompareWatcher();
sm.compareObject();
return true;
}
SelfScript.self['macrosЗагрузитьРезультатыСравнения'] = function(){
var sm = GetCompareWatcher();
sm.applyPath();
return true;
}
CompareWatcher = ScriptForm.extend({
settingsRootPath : SelfScript.uniqueName,
settings : {
pflSnegopat : {
'pathKdiff3' : "" // путь к kdiff
}
},
construct:function(){
this._super(SelfScript.fullPath.replace(/js$/, 'ssf'));
this.form.КлючСохраненияПоложенияОкна = "CompareWatcher.js"
this.modalForm=null;
this.compareForm=null;
this.re = new RegExp(/(Сравнение, объединение|Сравнение|Обновление)(\s(.*)\s-\s(.*))/);//new RegExp(/(Сравнение, объединение|Сравнение|Обновление)(.*)/);
this.title = "";
this.mergesObj = [];
this.loadSettings();
CompareWatcher._instance = this;
},
loadSettings:function(){
this._super();
stdcommands.Config.CompareDBCfg.addHandler(this, "onCompare");
stdcommands.CfgStore.MergeCfgStoreWithFile.addHandler(this, "onCompare");
stdcommands.CfgStore.MergeConfigWithCfgStore.addHandler(this, "onCompare");
},
onCompare:function (cmd) {
if(!cmd.isBefore)
{
logger.debug("CompareWatcher before start")
this.tempPath = TempFilesDir();
this.mergesObj = [];
events.connect(windows, "onDoModal", this);
} else {
//Message("Удалить лишние файлы.");
try {
events.disconnect(windows, "onDoModal", this);
} catch (e) { }
}
},
onDoModal :function(dlgInfo)
{
try{
if(openModalWnd == dlgInfo.stage && dlgInfo.caption == "Настройка объединения модулей" && dlgInfo.form){
logger.debug(dlgInfo.caption);
this.modalForm = dlgInfo.form;
es = this;
function foundCompareWindows(childs)
{
// При посылке команды окно стает активным, чтобы не нарушить порядок окон, переберем их
// в обратном порядке
for(var i = childs.count; i-- ; )
{
var view = childs.item(i)
if(view.isContainer != vctNo)
foundCompareWindows(view.enumChilds())
else
{
// Возможно, это окно формы, но не открыто на вкладке модуля
var r = view.title;
logger.debug("find "+r+"re "+es.re);
var mathes = r.match(es.re);
if (mathes && mathes.length) {
es.title = r
var caption = ''+windows.caption;
if (view.getInternalForm()){
logger.debug("found "+r);
es.compareForm = view.getInternalForm();
return;
}
}
//if(view.mdObj && view.mdProp && view.mdObj.isPropModule(view.mdProp.id))
// view.mdObj.openModule(view.mdProp.id) // переключим на вкладку модуля
}
}
}
//Найдем окно сравнени объектов конфигурации.
foundCompareWindows(windows.mdiView.enumChilds());
}
} catch(e){
logger.error(e.description);
}
},
foundCompareWindows:function(childs){
// При посылке команды окно стает активным, чтобы не нарушить порядок окон, переберем их
// в обратном порядке
for(var i = childs.count; i-- ; )
{
var view = childs.item(i)
if(view.isContainer != vctNo)
this.foundCompareWindows(view.enumChilds())
else
{
// Возможно, это окно формы, но не открыто на вкладке модуля
var r = view.title;
logger.debug("find "+r+"re "+this.re);
var mathes = r.match(this.re);
if (mathes && mathes.length) {
this.title = r
var caption = ''+windows.caption;
if (view.getInternalForm()){
logger.debug("found "+r);
this.compareForm = view.getInternalForm();
return;
}
}
//if(view.mdObj && view.mdProp && view.mdObj.isPropModule(view.mdProp.id))
// view.mdObj.openModule(view.mdProp.id) // переключим на вкладку модуля
}
}
},
setModuleForObj:function(mdObj){
if(!mdObj){
logger.error("установка модуля, не нашли объект метаданных");
return;
}
Message("Объединияем:"+mdObj.getTitle());
if (true){
if(!mdObj.isProcedure){ //Тут просто, это модуль, поэтому можем сразу весь и заливать.
if(mdObj.newText.length>0){
mdObj.obj.setModuleText(mdObj.prop, mdObj.newText);
//FIXME: Добавить настройку открытия этого же объекта сразу в конфигураторе.
mdObj.obj.editProperty(mdObj.prop);
}
} else {
//Тут сложнее. Нам надо получить полностью текст модуля и подменить его, по процедурно.
sourceText = mdObj.getText();
context = SyntaxAnalysis.AnalyseModule(sourceText, true);
var method = context.getMethodByName(mdObj.procedureName);
if (!method) {
logger.error("Для метода "+mdObj.procedureName+ " в исходном модуле, не нашли процедуры "+mdObj.getTitle());
return;
}
Lines = sourceText.split("\n");
beforeLines = Lines.slice(0, method.StartLine);
afterLines = Lines.slice(method.EndLine+1);
//debugger;
newLines = mdObj.newText;
newText = beforeLines.join("\n")+"\n" + mdObj.newText+"\n"+ afterLines.join("\n");
mdObj.obj.setModuleText(mdObj.prop, newText);
}
}
},
applyPath:function(){
//FIXME: показать форму со списком изменений и показа, что хотим загрузить.
//Пока тупо список значений...
var choiceList = v8New("ValueList");
for(var i = 0; i<this.mergesObj.length; i++){
logger.debug(""+this.mergesObj[i].getTitle() + " count:"+choiceList.Count());
choiceList.add(this.mergesObj[i], this.mergesObj[i].getTitle(), true);
}
if(!choiceList.CheckItems("Выбирите объекты для загрузки")){
return;
}
var choices = [];
var notChoice = [];
for(var i = 0; i<choiceList.count(); i++){
choice = choiceList.Get(i);
if(choice.check == true){
choices.push(choice.value);
} else {
notChoice.push(choice.value);
}
}
for(var i = 0; i<=choices.length; i++){
var mdObj = choices[i];
this.setModuleForObj(mdObj);
}
this.mergesObj = notChoice.slice(0);
},
compareProcedure:function(){
if(!this.modalForm || !this.compareForm){
logger.error("Не найденна модальная форма попроцедурного сравнения");
logger.error("modal "+!this.modalForm + "compare "+!this.compareForm);
return;
}
try{
grid = this.modalForm.getControl("Grid").extInterface;
if(grid.currentRow.getCellAppearance(0).text.length == 0)
return;
} catch (e){
return;
}
currentProcedure = grid.currentRow.getCellAppearance(0).text;
//Определим текущий модуль, полный путь.
diff = this.getDiff(currentProcedure);
if (!diff){
logger.error("not diff")
return;
}
this.merge(diff, currentProcedure);
},
getFullPath:function(parent, indent, fullPath){
if (parent.parent == null){
logger.info("parent null, return "+fullPath + " current "+parent.getCellAppearance(0).text);
return fullPath;
}
skips = {
"Свойства":true,
"Общие":true
}
propsName = {
"Модуль менеджера":"МодульМенеджера",
"Модуль объекта":"МодульОбъекта",
"Модуль набора записей":"МодульНабораЗаписей",
"Модуль менеджера значения":"МодульМенеджераЗначения",
"Общие модули":"ОбщиеМодули"
}
var name = parent.getCellAppearance(0).text;
if (skips[name]){
logger.info("getFullPath: skiped");
} else {
if(propsName[name]){
logger.info("getFullPath:сработала замена для "+name + " новое имя "+propsName[name]);
name = propsName[name];
}
fullPath = name + (fullPath.length ? "." : "")+fullPath;
}
if(parent.parent!=null){
return this.getFullPath(parent.parent, "", fullPath);
}
return fullPath;
},
compareObject:function(){
//Найдем окно сравнени объектов конфигурации.
this.foundCompareWindows(windows.mdiView.enumChilds());
if(!this.compareForm){
logger.error("Не найденна форма сравнения")
return;
}
if (!this.tempPath)
this.tempPath = TempFilesDir();
diff = this.getDiff();
this.diff(diff);
},
mergeObject:function(){
//Найдем окно сравнени объектов конфигурации.
this.foundCompareWindows(windows.mdiView.enumChilds());
if(!this.compareForm){
logger.error("Не найденна форма сравнения")
return;
}
diff = this.getDiff();
this.merge(diff);
},
getDiff:function(currentProcedure){
logger.info("getDiff");
if(!this.compareForm)
return;
fullPath = this.getFullPath(this.compareForm.activeControl.extInterface.currentRow, '', '');
logger.debug(this.tempPath);
logger.debug("full path:"+fullPath);
CreateDirectory(this.tempPath + "\\"+fullPath);
containers = {}
//Переберем все открытые контейнеры и сохраним их.
for(var i = 0, c = metadata.openedCount; i < c; i++)
{
var container = metadata.getContainer(i)
containers[container.identifier]=container;
logger.debug("opened container:"+container.identifier+":")
}
//Найдем объект метаданных
function getMdObj(rootObject, callArray){
found = false;
mdObject = null;
if (callArray.length > 3){
//Это по документам, справочникам и т.д. идем.
//metadataName = Matches[1].slice(0, Matches[1].indexOf('.'));
try{
mdObject1 = rootObject.childObject(callArray[0], callArray[1]);
if (mdObject1){
mdObject = mdObject1.childObject(callArray[2], callArray[3]);
if (mdObject){
found = true;
return new MdObject(mdObject, callArray[4]);
}
}
} catch(e){
logger.error("not found object", callArray);
logger.error("not found object", e.description);
}
} else if(callArray.length > 1 ) {
//Тут по общим модулям пройдемся.
try{
mdObject1 = rootObject.childObject(callArray[0], callArray[1]);
if (mdObject1){
found = true;
return new MdObject(mdObject1, callArray[2]);
}
} catch(e){
logger.error("not found object", callArray);
logger.error("not found object", e.description);
}
}
return;
}
diff = new diffObject(this.form.pathKdiff3, this.tempPath);
var mathes = this.title.match(this.re);
//Новая конфигурация поставщика
//Старая конфигурация поставщика
//Заголовок Обновлени Основная конфигурация - Новая конфигурация поставщика.
if (mathes && mathes.length) {
logger.debug(mathes);
if (containers["Старая конфигурация поставщика"]){ //Если это обновление, первым идет старая конфигурация, потом наша и третьей будет новая конфигурация поставщика.
logger.debug("Нашли старую кофнигурацию...")
var mdObject = getMdObj(containers["Старая конфигурация поставщика"].rootObject, fullPath.split("."));
diff.addA(mdObject);
if(containers[mathes[3]]){ //left
var mdObject = getMdObj(containers[mathes[3]].rootObject, fullPath.split("."));
diff.addB(mdObject);
}
if(containers[mathes[4]]){ //right
var mdObject = getMdObj(containers[mathes[4]].rootObject, fullPath.split("."));
diff.addC(mdObject);
}
} else {
if(containers[mathes[3]]){ //left
var mdObject = getMdObj(containers[mathes[3]].rootObject, fullPath.split("."));
logger.debug("add object "+mdObject.getTitle())
diff.addA(mdObject);
}
if(containers[mathes[4]]){ //right
var mdObject = getMdObj(containers[mathes[4]].rootObject, fullPath.split("."));
logger.debug("add object "+mdObject.getTitle())
diff.addB(mdObject);
}
}
} else {
logger.error("Не нашли в открытом окне конфигурации");
return ;
}
diff.fullPath = fullPath;
//diff.tempPath = this.tempPath
return diff;
},
merge:function(diff, procedureName){
if(!this.mergesObj){
this.mergesObj = [];
}
result = diff.mergeObjects(diff.fullPath, procedureName);
this.mergesObj.push(result);
},
diff:function(diff){
diff.diffObjects(diff.fullPath);
},
Ok_Click:function(Button){
this.saveSettings();
this.loadSettings();
this.form.Close();
},
Close_Click:function(Button){
this.form.Close();
},
pathKdiff3_StartChoice:function(element, СтандартнаяОбработка){
var ДиалогОткрытияФайла=v8New("ДиалогВыбораФайла", РежимДиалогаВыбораФайла.Открытие);
ДиалогОткрытияФайла.ПолноеИмяФайла = this.form.pathKdiff3;
ДиалогОткрытияФайла.Заголовок = "Выберите файл kdiff3 "
if(ДиалогОткрытияФайла.Выбрать()==false){
//element.val = ""
} else {
element.val.Значение = ДиалогОткрытияФайла.ПолноеИмяФайла;
СтандартнаяОбработка = false;
}
}
})
MdObject = stdlib.Class.extend({
construct: function (obj, prop, title) {
this.obj = obj;
this.prop = prop;
this.title = null;
this.md = obj.container;
this.isForm = (prop == "Форма");
},
getText: function() {
if (this.obj.isPropModule(this.prop))
return this.obj.getModuleText(this.prop);
return ""
},
saveTextToTempFile: function(path, procedureName){
if (!path) path = GetTempFileName('txt');
text = this.convertToText(procedureName);
var file = v8New("textDocument");
file.setText(text);
try{
file.Write(path);
} catch (e) {
return null;
}
return path;
},
activate: function() {
this.obj.openModule(this.prop);
return GetTextWindow();
},
getTitle: function() {
if (!this.title)
{
function getMdName(mdObj) {
if (mdObj.parent && mdObj.parent.mdClass.name(1) != 'Конфигурация')
return getMdName(mdObj.parent) + '.' + mdObj.mdClass.name(1) + '.' + mdObj.name;
var cname = mdObj.mdClass.name(1);
return (cname ? cname +'.':'') + mdObj.name;
}
this.title = getMdName(this.obj) + '.' + this.prop;
}
return this.title;
},
getForm: function(){
if (!this.isForm) {
return null
}
var tempPath = GetTempFileName('ssf');
var ep = this.obj.getExtProp("Форма");
var file = ep.saveToFile();
try{
// создадим хранилище на базе файла. Для управляемых форм тут вывалится в catch
var stg = v8Files.attachStorage(file);
// Получим из хранилища содержимое под-файла form
var form = ep.getForm();
var file1 = v8New("textDocument");
file1.setText(' ');
file1.Write(tempPath);
file1=null;
var file = ep.saveToFile(v8files.open("file://"+tempPath, fomIn | fomOut | fomTruncate));
file.close();
this.isManagmendForm = false;
} catch(e) {
//logger.error(e.description);
//isManagmendForm = true;
this.isManagmendForm = true;
file.seek(0, fsBegin)
var text = file.getString(dsUtf8);
var file = v8New("textDocument");
file.setText(text);
var tempPath = GetTempFileName('txt');
file.Write(tempPath);
newPath = GetTempFileName('ssf');
MoveFile(tempPath, newPath);
tempPath = newPath;
}
return tempPath;
},
convertToText:function(procedureName){
if(procedureName == undefined) return this.getText();
sourceText = this.obj.getModuleText(this.prop);
context = SyntaxAnalysis.AnalyseModule(sourceText, true);
var method = context.getMethodByName(procedureName);
if (!method) return "";
Lines = sourceText.split("\n");
var text = [];
for (var i = method.StartLine; i<=method.EndLine; i++){
text.push(Lines[i]);
}
return text.join("\n");
}
});
TextDocObject = stdlib.Class.extend({
construct: function (txtDoc, title) {
this.obj = txtDoc;
this.title = title;
},
getText: function() {
return this.obj.GetText();
},
activate: function() {
this.obj.Show();
return GetTextWindow();
},
getTitle: function() {
if (!this.title)
this.title = this.obj.UsedFileName;
return this.title;
}
});
diffObject = stdlib.Class.extend({
construct: function (mergeToolPath, tempPath) {
if(!mergeToolPath){
this.kdiffpath = "C:\\KDiff3\\kdiff3.exe";
} else {
this.kdiffpath = this.getAbsolutePath(mergeToolPath);
}
this.A = null;
this.B = null;
this.C = null;
logger.debug("Передан " + tempPath)
if(tempPath == undefined){
this.tempPath = TempFilesDir();
} else {
this.tempPath = tempPath;
}
logger.debug(this.tempPath);
},
addA : function(obj){
this.A = obj;
},
addB : function(obj){
this.B = obj;
//this.diffObjects();
},
addC : function(obj){
this.C = obj;
},
getAbsolutePath : function(path) {
// Путь относительный?
if (path.match(/^\.{1,2}[\/\\]/))
{
// Относительные пути должны задаваться относительно главного каталога Снегопата.
var mainFolder = profileRoot.getValue("Snegopat/MainFolder");
return mainFolder + path;
}
return path;
},
diffObjects: function(isModalMode){
//debugger;
if (!this.A || !this.B) {
Message("Не заполенны А или В");
return;
}
if (this.A.isForm = this.B.isForm) {
//diff form...
//diff files...
pathA = this.A.getForm();
if (!pathA) return;
logger.debug(pathA);
pathB = this.B.getForm();
if (!pathB) return
logger.debug(pathB)
if (!this.epfLoader){
try{
this.epfLoader = EpfLoader.getEpf("v8reader");
} catch (e){
this.epfLoader = null
logger.error("Не удалось загрузить epfloader обработку v8reader");
return text;
}
}
if (!this.epfLoader){
v8reader = stdlib.require(stdlib.getSnegopatMainFolder() + "scripts\\dvcs\\diff-v8Reader.js").GetBackend();
v8reader(pathA, pathB);
} else {
this.epfLoader.СравнитьФормы(pathA, pathB);
}
} else {
//diff files...
pathA = this.A.saveTextToTempFile();
if (!pathA) return;
pathB = this.B.saveTextToTempFile();
if (!pathB) return
if (this.C) {
pathC = this.C.saveTextToTempFile();
if (!pathC) return
pathC = ' '+pathC;
} else {
pathC = ''
}
var cmd = this.kdiffpath +' "'+pathA+'" "'+ pathB +'" '+ pathC;
//Message(""+cmd);
ЗапуститьПриложение(cmd, "", false);
}
},
mergeObjects:function(catalogPath, procedureName){
//debugger;
if (!this.A || !this.B) {
Message("Не заполенны А или В");
return;
}
pathA = this.A.saveTextToTempFile(null,procedureName);
if (!pathA) return;
//pathA = pathA + " --L1 base-"+catalogPath
pathB = this.B.saveTextToTempFile(null,procedureName);
if (!pathB) return
//pathB = pathB +" --L2 mine-"+catalogPath
if (this.C) {
pathC = this.C.saveTextToTempFile(null,procedureName);
if (!pathC) return
pathC = ' '+pathC;
} else {
pathC = ''
}
//--L1 alias1 Visible name replacement for input file 1 (base).
//--L2 alias2 Visible name replacement for input file 2.
//--L3 alias3
logger.debug(this.tempPath);
if (procedureName==undefined){
resultPath = this.tempPath + catalogPath+'\\'+ this.A.prop +'.txt';
} else {
resultPath = this.tempPath + catalogPath +'\\'+ procedureName+'.txt';
}
if (procedureName==undefined){
var cmd = this.kdiffpath +' "'+pathA+'" "'+ pathB +'" '+ pathC + ' -o '+ '"'+resultPath+'"' ;
} else {
var cmd = this.kdiffpath +' "'+pathA+'" "'+ pathB +'" '+ pathC + ' -o '+ '"'+resultPath+'"';
}
ЗапуститьПриложение(cmd, "", true);
if(!this.C){
mdObj = this.A;
} else {
mdObj = this.B;
}
if(procedureName == undefined){
mdObj.isProcedure = false;
} else {
mdObj.isProcedure = true;
mdObj.procedureName = procedureName;
}
//debugger;
textDoc = v8New("textDocument");
try{
textDoc.read(resultPath);
mdObj.newText = textDoc.GetText();
} catch(e){
mdObj.newText = "";
}
return mdObj;
},
clearCache: function () {
this.A = null;
this.B = null;
this.C = null;
}
});
function GetCompareWatcher() {
if (!CompareWatcher._instance)
new CompareWatcher();
return CompareWatcher._instance;
}
var cht = GetCompareWatcher();