YaST/Tutorials/Simple YaST Module/YaST Module Files

Перейти к: навигация, поиск

Файлы модуля YaST

Ранее было показано как создать модуль YaST, установить и запустить его. Далее будет больше рассказано об исходных файлах проекта: для чего они нужны, что они содержат и какие функции выполняют.

Файлы проекта и слои YaST

На рисунке ниже показано соответствие файлов проекта и слоев YaST. Так новые модули YaST должны быть разделены на файлы в соответствии с последней версией. Например, файла sshd.scr нет в недавно созданном шаблоне.

T1-yast-overview-files.png

Работа внутренних механизмов

Эта часть довольно сложная и не настолько важна - при желании ее можно пропустить.

Что происходит между вызовом команды /sbin/yast2 sshd и открытием диалогового окна?

  1. Скрипт /sbin/yast2 определяет внутренние переменные, такие как, например LC_CTYPE. Затем происходит проверка доступны ли библиотеки Qt или ncurses и выполняется бинарный файл /usr/lib/YaST2/bin/y2base.
  2. /usr/lib/YaST2/bin/y2base вызывает “sshd qt” или “sshd ncurses” как два параметра программы. y2base проверяет существует ли клиент sshd.ycp в каталоге /usr/share/YaST2/clients/ и запускает его.
  3. sshd.ycp импортирует различные бинарные модули Progress, Report или CommandLine, определяет параметры командной строки, а так же к sshd.ycp подключен файл wizards.ycp.
  4. К файлу wizarsds.ycp подключен файл dialogs.ycp с определением диалогов и файл complex.ycp c определением сложных функций диалогов и с определением последовательности диалогов.
  5. После закрытия пользовательского интерфейса управление возвращается клиенту sshd.ycp, который завершает операции и закрывается.

Обзор файлов с исходным кодом

Файлы исходного кода находятся в каталоге sshd/src/. Все эти файлы копируются каталог /usr/share/YaST2/ во время процедуры сборки и установки. Ниже рассмотрено назначение этих файлов на нескольких простых примерах. Файлы представлены здесь в упрощенном виде, большая часть информационного наполнения заменена многоточием. Важные части подчеркнуты. Файлы отсортированы согласно логики работы модуля.

Файл sshd.desktop

Параметры для приложений KDE, AutoYaST, центра управления YaST...

[Desktop Entry]
Type=Application
...
X-SuSE-YaST-Group=Misc
...
Icon=yast-sshd
Exec=/sbin/yast2 sshd
...
Name=Sshd
GenericName=sshd
...

Эти настройки используются другими приложениями, а не непосредственно конфигуратором YaST SSHD. Они определяют поведение и идентификацию модуля. Более подробное описание находится в YaST Desktop Files.

Файл sshd.ycp

Базовое клиентское приложение с поддержкой командной строки. Интерфейс командной строки будет описан в другой примере.

Клиенты хранятся в каталоге /usr/share/YaST2/clients/

/**
 * Файл: clients/sshd.ycp
 ...
 */

{

textdomain "sshd";

/* The main () */
y2milestone ("----------------------------------------");
y2milestone ("Sshd module started");

import "Progress";
import "Report";
import "Summary";

import "CommandLine";
include "sshd/wizards.ycp";

map cmdline_description = $[
    ...
    "guihandler" : SshdSequence,
    ...
];

/* это предлоежение или нет? */
boolean propose = false;
...

/* Функция main пользовательского интерфейса */
any ret = nil;

if (propose) ret = SshdAutoSequence();
else ret = CommandLine::Run(cmdline_description);
y2debug("ret=%1", ret);

/* Конец */
y2milestone("Sshd module finished");
y2milestone("----------------------------------------");

return ret;

/* Конец файла */
}

К этому модулю подключен файл wizard.ycp с описанием последовательности диалогов. Клиент запускает бинарный файл YaST, вызывает CommandLine::Run() which, в данном случае, SshdSequence() диалогового мастера wizard.ycp.

ЗАМЕЧАНИЕ: Существуют также и другие клиенты: <имя-модуля>_auto.ycp для AutoYaST и <имя-модуля>_ proposal.ycp для предложенной установки, но они ненужны в данном примере.

Файл wizards.ycp

Содержит описание последовательности диалогов, которые используются клиентами.

Мастера сохранены в каталоге /usr/share/YaST2/include/<module-name>/.

/**
 * Файл: include/sshd/wizards.ycp
 ...
 */

{

textdomain "sshd";

import "Sequencer";
import "Wizard";

include "sshd/complex.ycp";
include "sshd/dialogs.ycp";

/**
 * Добавить в конфигуратор sshd
 * полученную последовательность диалогов
 */
any AddSequence() {
    ...
}

/**
 * Основной мастер конфигуратора sshd
 * создает последовательность диалогов
 */
any MainSequence() {

    map aliases = $[
	"summary"	:   ``( SummaryDialog() ),
	"overview"	:   ``( OverviewDialog() ),
	"add"		: [ ``( AddSequence() ), true ],
	"edit"		: [ ``( AddSequence() ), true ]
    ];

    map sequence = $[
	"ws_start" : "summary",
	"summary" : $[
	    `abort	: `abort,
	    `next	: `next,
	    `overview	: "overview",
	],
	"overview" : $[
	    `abort	: `abort,
	    `next	: `next,
	    `add	: "add",
	    `edit	: "edit",
	],
	"add" : $[
	    `abort	: `abort,
	    `next	: "overview",
	],
	"edit" : $[
	    `abort	: `abort,
	    `next	: "overview",
	]
    ];

    any ret = Sequencer::Run(aliases, sequence);

    return ret;
}

/**
 * Возвращается по результатам обработки последовательности диалогов 
 * вся конфигурация sshd
 */
any SshdSequence() {

    map aliases = $[
	"read"	: [ ``( ReadDialog() ), true ],
	"main"	:   ``( MainSequence() ),
	"write"	: [ ``( WriteDialog() ), true ]
    ];

    map sequence = $[
	"ws_start" : "read",
	"read" : $[
	    `abort	: `abort,
	    `next	: "main"
	],
	"main" : $[
	    `abort	: `abort,
	    `next	: "write"
	],
	"write" : $[
	    `abort	: `abort,
	    `next	: `next
	]
    ];

    Wizard::CreateDialog();

    any ret = Sequencer::Run(aliases, sequence);

    UI::CloseDialog();
    return ret;
}

/**
 * Возвращает вся конфигурацию sshd, но не для чтения или записи, а
 * для автоустановки
 */
any SshdAutoSequence() {
    ...
}

/* Конец файла */
}

В начале модуля подключены файлы complex.ycp и dialogs.ycp, потому что они содержат диалоги, которые используются в последовательностях диалогов.

Ниже в карте псевдонимов (aliases map) определены псевдонимы (aliases) к этим диалогам, а последовательности (sequences), использующие эти псевдонимы, определены в карте последовательностей (sequence map). В обработчике последовательности диалогов определена связь между событием (event) генерируемым диалоговой функцией и действием (action) вызванным последовательностью.

SshdSequence() вызывается в конце клиента sshd.ycp.

ВАЖНО: Не надо создавать событие для кнопки «Назад» (Back), диалоговый мастер обрабатывает его самостоятельно.

ЗАМЕЧАНИЕ:

Стоит отметить что последовательности могут вызывать другие последовательности: SshdSequence() вызывает MainSequence() и все вызывают AddSequence().

Последовательность вызванная клиентом должна содержать команды Wizard::CreateDialog() и UI::CloseDialog(), так как пользователь должен увидеть интерфейс как можно раньше. Кроме этого команда Wizard::CreateDialog() создает классический окно мастера с текстом справки с левой стороны, пустым пространством на другой стороне и кнопками «Назад» (Back), «Отмена» (Abort) и «Далее» (Next).

Скриншот окна Мастера:

T1-blind-wizard.png

Файл dialogs.ycp

В этом файле определены диалоги и их простейшие обработчики.

Диалоги хранятся в каталоге /usr/share/YaST2/include/<имя-модуля>/

/**
 * Файл: include/sshd/dialogs.ycp
 ...
 */

{

textdomain "sshd";

import "Label";
import "Wizard";
import "Sshd";

include "sshd/helps.ycp";

/**
 * Configure1Dialog
 * возвращает результат диалога
 */
any Configure1Dialog () {

    /* Sshd configure1 dialog caption */
    string caption = _("Sshd Configuration");

    /* Sshd configure1 dialog contents */
    term contents = `Label (_("First part of configuration of sshd"));

    Wizard::SetContentsButtons(caption, contents, HELPS["c1"]:"",
	    Label::BackButton(), Label::NextButton());

    any ret = nil;
    while (true) {

	ret = UI::UserInput();

	/* abort? */
	if(ret == `abort || ret == `cancel) {
	    if(ReallyAbort()) break;
	    else continue;
	}
        else if(ret == `next || ret == `back) {
            break;
        }
        else {
            y2error("unexpected retcode: %1", ret);
            continue;
        }
    }

    return ret;
}

/**
 * Configure2Dialog
 * возвращает результат диалога
 */
any Configure2Dialog () {
    ...
}

/* Конец файла */
}

В этом файле определены две функции диалогов Configure1Dialog() и Configure2Dialog(). Поведение диалогов определяется в функцией Wizard::SetContentsButtons().Эта дополнительная функция доступна потому что в файле wizard.ycp используется Wizard::CreateDialog()

После того как создан диалог, запускается цикл в котором обрабатываются действия пользователя.

Текст помощи находиться в файле helps.ycp в виде справочной карты (HELPS map).

ЗАМЕЧАНИЕ: Все строки которые нуждаются в переводе записаны следующим образом _("...") . Перед каждой такой строкой должен быть комментарий для переводчика. Здесь используется стандартный стиль gettext.

Переводы жестко связаны с текстовыми доменами (textdomain) внутри файла.

File complex.ycp

Модуль содержит сложные функции для обработки диалогов.

/**
 * Файл: include/sshd/complex.ycp
 ...
 */

{

textdomain "sshd";

import "Label";
...
import "Sshd";


include "sshd/helps.ycp";

...

/**
* Диалог чтения настроек
* возвращает`abort в случае отмены и `next в противном случае
 */
symbol ReadDialog() {
    Wizard::RestoreHelp(HELPS["read"]:"");
    // Sshd::AbortFunction = PollAbort;
    if (!Confirm::MustBeRoot()) return `abort;
    boolean ret = Sshd::Read();
    return ret ? `next : `abort;
}

/**
* Диалог записи настроек
* возвращает`abort в случае отмены и `next в противном случае
 */
symbol WriteDialog() {
    ...
}

/**
 * SummaryDialog
 * возвращает результат диалога
 */
any SummaryDialog() {
    ..
}

/**
 * OverviewDialog
 * возвращает результат диалога
 */
any OverviewDialog() {

    /* заголовок диалогового окна */
    string caption = _("Sshd Overview");

    list overview = Sshd::Overview();

    /* шапка таблицы FIXME */
    term contents = Wizard_hw::ConfiguredContent(
	/* шапка таблицы */
	`header(_("Number"), _("Sshd")),
	overview, nil, nil, nil, nil );

    contents = Wizard_hw::SpacingAround(contents, 1.5, 1.5, 1.0, 1.0);

    Wizard::SetContentsButtons(caption, contents, HELPS["overview"]:"",
	    Label::BackButton(), Label::FinishButton());

    any ret = nil;
    while (true) {

	ret = UI::UserInput();

	/* отмена? */
	if(ret == `abort || ret == `cancel) {
	    if(ReallyAbort()) break;
	    else continue;
	}
        /* добавить */
        else if(ret == `add_button) {
            ret = `add;
            break;
        }
        /* править */
        else if(ret == `edit_button) {
            ret = `edit;
            break;
        }
        /* удалить */
        else if(ret == `delete_button) {
            continue;
        }
        else if(ret == `next || ret == `back) {
            break;
        }
        else {
            y2error("unexpected retcode: %1", ret);
            continue;
        }
    }

    return ret;
}

/* Конец файла */
}

Этот файл очень похож на dialogs.ycp, но здесь находятся более сложные диалоги с обработчиками.

Самое важное здесь это обращение функции ReadDialog() к Sshd::Read() – это глобальная функция YCP модуля Sshd.

При просмотре файла wizards.ycp можно увидеть что в его карте псевдонимов используются диалоговые функции, определенные в модуле complex.ycp.

Файл helps.ycp

Содержит тексты справки для каждого диалога.

Справка храниться в каталоге /usr/share/YaST2/include/<имя-модуля>/

/**
 * Файл: include/sshd/helps.ycp
 ...
 */

{

textdomain "sshd";

/**
 * Вся справка здесь
 */
map HELPS = $[

    /* Справка диалога чтения 1/2 */
    "read" : _("<p><b><big>Initializing sshd Configuration</big></b><br>
Please wait...<br></p>
") +

    /* Справка диалога чтения 2/2 */
    _("<p><b><big>Aborting Initialization:</big></b><br>
Safely abort the configuration utility by pressing <b>Abort</b> now.</p>
"),

...

    /* Справка диалога Configure1 1/2 */
    "c1" : _("<p><b><big>Configuration Part One</big></b><br>
Press <b>Next</b> to continue.
<br></p>") +

    /* Справка диалога Configure1 2/2 */
    _("<p><b><big>Selecting Something</big></b><br>
It is not possible. You must code it first. :-)
</p>"),

...

];

/* Конец файла */
}

Этот файл включен в модули dialogs.ycp и complex.ycp. Все тексты определены в карте HELPS.

Все справочные тексты пишутся на HTML и они должны соответствовать Text Style Guide.

ЗАМЕЧАНИЕ: Тексты справки логически делятся на небольшие части. Так после изменений переводчикам легче переводить небольшие блоки текста.

Файл Sshd.ycp

YCP модуль с глобальным API, который может использоваться другими модулями или проектами.

Все модули хранятся в каталоге /usr/share/YaST2/modules/.

/**
 * File:        modules/Sshd.ycp
 * Package:     Конфигуратор sshd
 * Summary:     Настройки sshd, функции ввода и вывода
 * Authors:     John The Fish <john@thesmallfish.net>
 *
 * $Id: Sshd.ycp 27914 2006-02-13 14:32:08Z jtf $
 *
 * Представление конфигурации sshd.
 * Процедуры ввода и вывода.
 */

{

module "Sshd";
textdomain "sshd";

...

/**
 * Чтение всех настроек sshd
 * возвращает true в случае удачи
 */
global boolean Read() {
    /* Заголовок диалога чтения sshd */
    string caption = _("Initializing sshd Configuration");
    ...
    integer steps = 4;
    ...
    Progress::New( caption, " ", steps, [
	...
	], [
	...
	],
	""
    );
    ...
    Progress::NextStage();
    ...
    if(Abort()) return false;
    modified = false;
    return true;
}

/**
 * Запись всех настроек sshd
 * возвращает true в случае удачи
 */
global boolean Write() {
    /* Заголовок диалога записи sshd */
    string caption = _("Saving sshd Configuration");
    ...
    integer steps = 4;
    ...
    Progress::New( caption, " ", steps, [
	...
	], [
	...
	],
	""
    );
    ...
    Progress::NextStage();
    ...
    if(Abort()) return false;
    return true;
}

...
}

Ключевое слово module устанавливает пространство имен модуля. Для доступа к глобальным функциям и переменным используется префикс имя_модуля:: (например Sshd:: для модуля Sshd).

В глобальных функциях Read и Write так же определена полоса прогресса (Progress bar), которая изменяется вызовом функции Progress::NextStage().

Функции Read и Write всегда должны сообщать результат работы возвращая значение типа boolean (выполнено, не выполнено).

ЗАМЕЧАНИЕ: Проект так же содержит файл Sshd.pm представляющий собой модуль написанный на языке Perl. Модуль Perl используется так же как и модуль YCP, но его внутренний синтаксис отличается. Создание Perl модулей в этом руководстве не рассматривается.

Далее