Эффективный способ пакетного импорта XMI в Enterprise Architect

Наша команда использует Enterprise Architect version 10 и SVN для репозитория. Поскольку размер файла EAP довольно большой (например, 80 МБ), мы экспортируем каждый пакет в отдельный XMI и сохраняем его в SVN. Сам файл EAP фиксируется после некоторого рубежа. Проблема заключается в том, чтобы синхронизировать файл EAP с работой коллеги во время разработки, нам нужно импортировать много XMI (например, всего может быть 500 файлов).

Я знаю, что после обновления файла EAP мы можем использовать Package Control -> Get All Latest. Поэтому эта проблема возникает только при параллельной разработке.

Мы использовали сочетания клавиш для импорта следующим образом:

  1. Ctrl+Alt+I (Импорт пакета из XMI файла)
  2. Выберите имя файла для импорта
  3. Alt+I (импорт)
  4. Ввести (Да)
  5. Повторяйте шаги со 2 по 4, пока модуль не будет завершен.

Но все же импорт сотен файлов неэффективен.

Я проверил, что в пакете управления есть пакетный импорт/экспорт. Пакетный импорт/экспорт работает, когда я явно жестко запрограммировал XMI Filename, но параметры недоступны при использовании контроля версий (параметры пакетного импорта/экспорта выделены серым цветом).

Есть ли лучшие способы синхронизации файлов EAP и XMI?


person David    schedule 24.05.2013    source источник


Ответы (2)


В EA есть интерфейс скриптов. Возможно, вы сможете автоматизировать импорт, используя это. Я не использовал это, но это, вероятно, очень хорошо.

Я не уверен, что полностью понимаю вашу рабочую среду, но у меня есть некоторые общие моменты, которые могут представлять интерес. Возможно, если вы используете EA по-другому (особенно мой первый пункт ниже), необходимость в пакетном импорте может исчезнуть.

Несколько сотрудников

Во-первых, над одним и тем же файлом EAP одновременно могут работать несколько человек. Файл EAP представляет собой не что иное, как файл базы данных Access, и EA использует блокировку, чтобы предотвратить одновременное редактирование одного и того же пакета несколькими людьми. Но вы можете комфортно иметь несколько человек, редактирующих разные пакеты в одном файле EAP одновременно. Поместить файл EAP в какой-нибудь общий файловый ресурс — хороший способ сделать это.

Встроенный контроль версий

Во-вторых, EA может напрямую взаимодействовать с SVN (и другими системами контроля версий). См. это. Короче говоря, вы можете настроить свой файл EAP так, чтобы отдельные пакеты (и все, что ниже их) контролировалось SVN. Затем вы можете проверить отдельный пакет, отредактировать его, вернуть обратно. Или вы можете проверить всю ветку под пакетом (включая подпакеты, которые сами контролируются SVN).

Под капотом EA импортирует и экспортирует файлы XMI и проверяет их в SVN и из него, в то время как файл EAP всегда является головной версией. Так же, как то, что вы делаете вручную, но автоматизировано. Это имеет смысл, учитывая, что вы все можете использовать один файл EAP. Вы должны быть немного осторожны при откате - ссылки, исходящие от объектов в более старых версиях одного пакета, могут указывать на объекты, которые больше не существуют (но вы можете посмотреть ошибки журнала импорта, чтобы увидеть, так ли это). К этому нужно немного привыкнуть, но работает довольно хорошо.

Существует также встроенная функция базового уровня пакетов — в любом случае это может быть все, что вам нужно, и работает довольно хорошо, особенно если вы все используете один и тот же файл EAP.

Увеличенный движок базы данных

В-третьих, вам вообще не обязательно иметь файл EAP. База данных модели может находиться в любой подходящей системе баз данных (MySQL, SQL Server, Oracle и т. д.). Таким образом, это дает вам всевозможные варианты масштабирования того, как он используется, как он работает в глобальной сети/Интернете и т. д.

Короче говоря, Sparx весьма разумно отнесся к тому, как EA можно использовать в среде с несколькими работниками, и это стоит использовать.

person bazza    schedule 01.06.2013
comment
Хорошо, позвольте мне проверить сценарии и встроенный контроль версий. - person David; 03.06.2013
comment
Встроенный контроль версий аналогичен тому, что мы делали прямо сейчас. Нет проблем с регистрацией пакета в SVN и получением экспорта XMI. Проблема заключается в первом импорте XMI, потому что каждый член команды использует свой собственный файл EAP. Для сценариев я видел только несколько примеров и пояснений :( - person David; 04.06.2013
comment
Файл EAP каждого члена команды номинально идентичен? Если это так, вы можете просто выбрать тот, который полностью обновлен (или сделать его таким), прикрепить его к файлообменнику, и тогда каждый сможет отказаться от своего и начать использовать этот. Затем вы можете настроить этот единственный файл EAP для интеграции с SVN. Вы потеряете преемственность в истории изменений. Короче говоря, я предлагаю разовую попытку получить один файл EAP, а затем с этого момента использовать встроенную автоматическую интеграцию EA с SVN. - person bazza; 05.06.2013
comment
Каждый член команды начинает с одного и того же файла EAP (не общего, а индивидуальной копии)). Позже каждый из них работает с разными пакетами. Таким образом, мы можем взять только один из EAP и по-прежнему должны импортировать пакеты, разработанные другими членами команды. - person David; 05.06.2013
comment
Если вы хотите работать над одним общим файлом EAP, вы можете сделать следующее. Попросите членов команды объединиться в пары и позвольте им создать между собой один файл EAP. Затем берет эти результаты, объединяет их в пары и так далее. Перейти от например. 16 EAP по 8, 4, 2, 1. Должно быть довольно быстро - person bazza; 05.06.2013
comment
Если вы все рассредоточены и у вас нет общей папки, которую вы все могли бы использовать, тогда, возможно, ответом будет распределенная база данных, подключенная к глобальной сети, а не файлы EAP. Вроде неплохо работает. - person bazza; 05.06.2013

Я создал скрипт советника, используя JScript для автоматизации.

Вот скрипт для экспорта:

!INC Local Scripts.EAConstants-JScript

/*
 * Script Name : Export List of SVN Packages
 * Author      : SDK
 * Purpose     : Export a package and all of its subpackages information related to version 
 *               controlled. The exported file then can be used to automatically import
 *               the XMIs
 * Date        : 30 July 2013
 * HOW TO USE  : 1. Select the package that you would like to export in the Project Browser
 *               2. Change the output filepath in this script if necessary.
 *                  By default it is "D:\\EAOutput.txt"
 *               3. Send the output file to your colleague who wanted to import the XMIs
 */

var f; 

function main()
{
    // UPDATE THE FOLLOWING OUTPUT FILE PATH IF NECESSARY
    var filename = "D:\\EAOutput.txt";

    var ForReading = 1, ForWriting = 2, ForAppending = 8;

    Repository.EnsureOutputVisible( "Script" );
    Repository.ClearOutput( "Script" );
    Session.Output("Start generating output...please wait...");

    var treeSelectedType = Repository.GetTreeSelectedItemType();

    switch ( treeSelectedType )
    {
        case otPackage:
        {
            var fso = new ActiveXObject("Scripting.FileSystemObject");
            f = fso.OpenTextFile(filename, ForWriting, true);

            var selectedObject as EA.Package;
            selectedObject = Repository.GetContextObject();
            reportPackage(selectedObject);
            loopChildPackages(selectedObject);

            f.Close();
            Session.Output( "Done! Check your output at " + filename);
            break;
        }
        default:
        {
            Session.Prompt( "This script does not support items of this type.", promptOK );
        }
    }
}

function loopChildPackages(thePackage)
{
    for (var j = 0 ; j < thePackage.Packages.Count; j++)
    {
        var child as EA.Package;
        child = thePackage.Packages.GetAt(j);
        reportPackage(child);
        loopChildPackages(child);
    }
}

function getParentPath(childPackage)
{
    if (childPackage.ParentID != 0)
    {
        var parentPackage as EA.Package;
        parentPackage =  Repository.GetPackageByID(childPackage.ParentID);
        return getParentPath(parentPackage) + "/" + parentPackage.Name;
    }
    return "";
}

function reportPackage(thePackage)
{
    f.WriteLine("GUID=" + thePackage.PackageGUID + ";"
                   + "NAME=" + thePackage.Name + ";" 
                   + "VCCFG=" + getVCCFG(thePackage) + ";" 
                   + "XML=" + thePackage.XMLPath + ";"
                   + "PARENT=" + getParentPath(thePackage).substring(1) + ";"
    );
}

function getVCCFG(thePackage)
{
    if (thePackage.IsVersionControlled)
    {
        var array = new Array();
        array = (thePackage.Flags).split(";");

        for (var z = 0 ; z < array.length; z++)
        {
            var pos = array[z].indexOf('=');

            if (pos > 0)
            {
                var key = array[z].substring(0, pos);
                var value = array[z].substring(pos + 1);

                if (key=="VCCFG")
                {
                    return (value);
                }
            }
        }
    }
    return "";
}

main();

И скрипт для импорта:

!INC Local Scripts.EAConstants-JScript

/*
 * Script Name : Import List Of SVN Packages
 * Author      : SDK
 * Purpose     : Imports a package with all of its sub packages generated from 
 *               "Export List Of SVN Packages" script
 * Date        : 01 Aug 2013
 * HOW TO USE  : 1. Get the output file generated by "Export List Of SVN Packages" script
 *                  from your colleague
 *               2. Get the XMIs in the SVN local copy
 *               3. Change the path to the output file in this script if necessary (var filename).
 *                  By default it is "D:\\EAOutput.txt"
 *               4. Change the path to local SVN
 *               5. Run the script
 */

var f; 
var svnPath;

function main()
{
    // CHANGE THE FOLLOWING TWO LINES ACCORDING TO YOUR INPUT AND LOCAL SVN COPY
    var filename = "D:\\EAOutput.txt";
    svnPath = "D:\\svn.xxx.com\\yyy\\docs\\design\\";

    var ForReading = 1, ForWriting = 2, ForAppending = 8;

    Repository.EnsureOutputVisible( "Script" );
    Repository.ClearOutput( "Script" );
    Session.Output("[INFO] Start importing packages from " + filename + ". Please wait...");

    var fso = new ActiveXObject("Scripting.FileSystemObject");
    f = fso.OpenTextFile(filename, ForReading);

    // Read from the file and display the results.
    while (!f.AtEndOfStream)
    {
        var r = f.ReadLine();
        parseLine(r);
        Session.Output("--------------------------------------------------------------------------------");
    }

    f.Close();
    Session.Output("[INFO] Finished");
}

function parseLine(line)
{
    Session.Output("[INFO] Parsing " + line);

    var array = new Array();
    array = (line).split(";");

    var guid;
    var name;
    var isVersionControlled;
    var xmlPath;
    var parentPath;

    isVersionControlled = false;
    xmlPath = "";

    for (var z = 0 ; z < array.length; z++)
    {
        var pos = array[z].indexOf('=');

        if (pos > 0)
        {
            var key = array[z].substring(0, pos);
            var value = array[z].substring(pos + 1);

            if (key=="GUID") {
                guid = value;
            } else if (key=="NAME") {
                name = value;
            } else if (key=="VCCFG") {
                if (value != "") {
                    isVersionControlled = true;
                }
            } else if (key=="XML") {
                if (isVersionControlled) {
                    xmlPath = value;
                }
            } else if (key=="PARENT") {
                parentPath = value;
            }
        }
    }

    // Quick check for target if already exist to speed up process
    var targetPackage as EA.Package;
    targetPackage = Repository.GetPackageByGuid(guid);
    if (targetPackage != null)
    {
        // target exists, do not do anything
        Session.Output("[DEBUG] Target package \"" + name + "\" already exist");
        return;
    }

    var paths = new Array();
    var packages = new Array(paths.Count);

    for (var i = 0; i < paths.Count; i++)
    {
        packages[i] = null;
    }

    paths = (parentPath).split("/");

    if (paths.Count < 2)
    {
        Session.Output("[INFO] Skipped root or level1");
        return;
    }

    packages[0] = selectRoot(paths[0]);
    packages[1] = selectPackage(packages[0], paths[1]);

    if (packages[1] == null)
    {
        Session.Output("[ERROR] Cannot find " + paths[0] + "/" + paths[1] + "in Project Browser");
        return;
    }

    for (var j = 2; j < paths.length; j++)
    {
        packages[j] = selectPackage(packages[j - 1], paths[j]);
        if (packages[j] == null)
        {
            Session.Output("[DEBUG] Creating " + packages[j].Name);

            // create the parent package
            var parent as EA.Package;
            parent = Repository.GetPackageByGuid(packages[j-1].PackageGUID);
            packages[j] = parent.Packages.AddNew(paths[j], "");
            packages[j].Update();
            parent.Update();
            parent.Packages.Refresh();
            break;
        }
    }

    // Check if name (package to import) already exist or not
    var targetPackage = selectPackage(packages[paths.length - 1], name);

    if (targetPackage == null)
    {
        if (xmlPath == "")
        {
            Session.Output("[DEBUG] Creating " + name);

            // The package is not SVN controlled
            var newPackage as EA.Package;
            newPackage = packages[paths.length - 1].Packages.AddNew(name,"");
            Session.Output("New GUID = " + newPackage.PackageGUID);
            newPackage.Update();
            packages[paths.length - 1].Update();
            packages[paths.length - 1].Packages.Refresh();
        }
        else
        {
            // The package is not SVN controlled
            Session.Output("[DEBUG] Need to import: " + svnPath + xmlPath);

            var project as EA.Project;
            project = Repository.GetProjectInterface;
            var result;

            Session.Output("GUID = " + packages[paths.length - 1].PackageGUID);
            Session.Output("GUID XML = " + project.GUIDtoXML(packages[paths.length - 1].PackageGUID));
            Session.Output("XMI file = " + svnPath + xmlPath);
            result = project.ImportPackageXMI(project.GUIDtoXML(packages[paths.length - 1].PackageGUID), svnPath + xmlPath, 1, 0);
            Session.Output(result);

            packages[paths.length - 1].Update();
            packages[paths.length - 1].Packages.Refresh();
        }

    }
    else
    {
        // target exists, do not do anything
        Session.Output("[DEBUG] Target package \"" + name + "\" already exist");
    }
}

function selectPackage(thePackage, childName)
{
    var childPackage as EA.Package;
    childPackage = null;

    if (thePackage == null)
        return null;

    for (var i = 0; i < thePackage.Packages.Count; i++)
    {
        childPackage = thePackage.Packages.GetAt(i);

        if (childPackage.Name == childName)
        {
            Session.Output("[DEBUG] Found " + childName);
            return childPackage;
        }
    }

    Session.Output("[DEBUG] Cannot find " + childName);
    return null;
}

function selectRoot(rootName)
{
    for (var y = 0; y < Repository.Models.Count; y++)
    {
        root = Repository.Models.GetAt(y);
        if (root.Name == rootName)
        {
            return root;
        }
    }
    return null;
}

main();
person David    schedule 01.08.2013