Tkabber Wiki

Разработка плагинов
Login

Разработка плагинов

Материал из Tkabber Wiki

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

Содержание

С чего начать

Прежде всего, вам необходимо желание написать плагин. Без этого никак. Если вы вообще тикль видите впервые, а плагин хочется (и никто его не пишет), то вам нужно огромное желание.

Учите матчасть

Выучите вы уже этот тикль, не бойтесь — он несложный

Первым практическим шагом станет изучение основ этого самого тикля. В статье Ссылки есть немало линков на различные ресурсы (в том числе и русскоязычные) по этому языку. В принципе, чтения книги самого Аустерхаута, дополненное занятиями, предложенными на этом сайте, должно хватить, чтобы начать мало-мальски в нём разбираться. Ещё один ценный источник информации, который всегда под рукой — мануалы: например, man 3tcl if и man 3tk frame (маны доступны и в интернете, но xterm всё же ближе). Могу вас успокоить — это вам не си-плюс-плюс, не перл и не питон (не знаю ни одного из этих языков, но могу голову дать на отсечение — тикль вы выучите на порядок быстрее любого из них). Спорим, что двух недель вам хватит? ;-P

Изучите документацию и исходники

Практические советы

Структура плагина

Структура каталога

Про это коротко, но ясно рассказано здесь.

Структура файла скрипта

Информация о плагине

В самом начале обычно пишутся некоторые данные о плагине и его авторе, в виде комментариев. Если вы не планируете делать развёрнутое описание плагина в отдельном файле, можете здесь же вкратце указать, как им пользоваться. Я поначалу так и сделал. Не забудьте дать свою контактную информацию (мыло, джаббер).

Задание пространства имён

"Во первы́х строка́х письма" © В. С. В. желательно определить пространство имён для процедур и переменных плагина, на случай, если вам взбредёт в голову назвать одну из процедур, к примеру, join_group (в muc.tcl есть такая процедура, и, чтобы не возникло путаницы и непонятно откуда берущихся ошибок, лучше это пресечь уже сейчас). Более того, как советуют знающие люди, если вы точно не знаете зачем вам поступать по-другому, все процедуры и переменные вашего плагина должны быть в своём пространстве имён. Также следует помнить, что загрузка плагинов делается кодом, который выполняется внутри namespace eval ::plugins, поэтому 1) собственное пространство имён не должно быть абсолютным (без веской причины) 2) надо везде использовать [namespace current], если требуется получить полное имя переменной/процедуры. Чтобы не ходить далеко за примером, разберу свой плагин.

namespace eval bldjid {
   ::msgcat::mcload [file join [file dirname [info script]] msgs]
   hook::add generate_completions_hook \
       [namespace current]::command_comps
   hook::add chat_send_message_hook \
       [namespace current]::handle_commands 17
}

Как видите, для задания пространства имён нужна команда namespace. Внутри фигурных скобок пишется то, что будет действовать в пределах этого пространства. Например, можно задавать хуки, устанавливать переменные или подгружать файлы сообщений, как во второй строчке примера. Немного подробнее о хуках можно почитать тут. Обратите внимание, имена хуков и их обработчиков я стырил из плагина-донора, но, чтобы мои обработчики не перепутались с оригинальными, к ним спереди прибавляется текущее пространство имён: при выполнении скрипта [namespace current] заместится на bldjid и получится bldjid::command_comps (см. объяснение ниже).

Строго говоря, в том плагине они тоже работают внутри своего пространства, поэтому с нашими не перепутаются, но лучше сделать всё по-человечески. С пространствами имён надо быть осторожнее и лучше перестраховываться, добавляя [namespace current]:: перед именем вызываемой процедуры. Дело в том, что пространство имён плагина само становится "отпрыском" пространства имён ::plugins — Это означает, что если вызывать процедуру вот так:

bldjid::command_comps

мы получим ошибку о неправильном имени этой команды. Так что если быть точнее, то при выполнении скрипта [namespace current] заместится на ::plugins::bldjid. Или можно ещё вызывать процедуру безо всяких неймспейсов, если вы уверены, что это имя уникально. Если же вы использовали какую-то чужую процедуру и не поменяли ей имя, не забудьте про пространство имён!

Настройки плагина

Если вы планируете делать плагин настраиваемым, после объявления неймспейса добавьте необходимые настройки. Вот пара настроек из плагина reversi:

   custom::defgroup Plugins [::msgcat::mc "Plugins options."] -group Tkabber
   custom::defgroup Reversi [::msgcat::mc "Reversi plugin options."] -group Plugins
   custom::defvar options(theme) Checkers \
   [::msgcat::mc "Reversi figures theme."] -group Reversi \
   -type options -values $values \
   -command [namespace current]::load_stored_theme

Смело копируйте эти или другие настройки себе и модифицируйте под свои нужды.

Тело плагина

Далее идут процедуры. Как минимум должны иметься процедуры-обработчики ваших хуков. Нужны ли вам другие — решать вам в зависимости от ваших потребностей, возможностей и стиля программирования. Вот для примера маленькая процедура-обработчик, которую я взял из urlcmd и адаптировал под себя:

proc bldjid::command_comps {chatid compsvar wordstart line} {
   upvar 0 $compsvar comps
   if {!$wordstart} {
       lappend comps {/bldjid } {/unbldjid } {/banjid }
   }
}

Обратите внимание на пространство имён bldjid, которое идёт перед именем процедуры (и отделяется от имени двумя двоеточиями). Его надо добавлять ко всем именам процедур скрипта, которые должны относиться к объявленному неймспейсу. Почувствуйте разницу: в utils.tcl имена процедур пишутся без пространства, потому что это базовые процедуры, и они выполняются в базовом пространстве Ткаббера — :: — и вызываются потом из других скриптов напрямую. Ещё обратите внимание на команды {/bldjid } {/unbldjid } {/banjid }, которые добавляются в список comps. Поначалу у меня были только две первые. Когда они заработали, я решил добавить бан по джиду в текущей комнате. Процедуру-то соответствующую дописал, а сюда команду добавить забыл и потом долго удивлялся, почему она не работает :)

Структура стандартного плагина примерно такова, но иногда (например, в плагине custom-urls.tcl) в самом конце снова объявляется пространство имён, но уже с другой начинкой.

(!) Сделать: Уточнить и рассказать про это.

Анализируйте чужой код и не бойтесь экспериментировать

Закончим анализ разбиравшегося плагина

Вторая процедура — bldjid::handle_commands — тоже обработчик хука (помните объявление пространства имён?). Её начало я тоже слямзил из urlcmd.tcl, а остальное — из muc.tcl. В процессе допиливания чужого кода выяснилось, что мне нужны ещё процедуры. Для команды /unbldjid мне идеально подошла внешняя: muc::unban, и я просто вызываю её в цикле. Так что разбанивание у меня заработало раньше забанивания :)

С баном вышло посложнее: я не знал, как лучше всё сделать, и поначалу пошёл по неправильному пути — начал изучать процедуры запроса, получения и отсылки чёрного списка (последняя из них — muc::send_list). Процедуры большие и выглядят довольно кошмарно (для новичка), но самое главное, что мне не нравилось — это необходимость вытягивать весь список только для того, чтобы прибавить к нему своего пациента и отправить весь список снова на сервер. Очень нерационально! И тут мне случайно на глаза попался такой комментарий в процедуре-обработчике muc::change_item_param, который обрабатывает команды Ткаббера /ban, /kick, /admin и другие: For unknown reason banning request MUST be based on user's bare JID (which may be not known by admin). "Опа, — подумал я, — так значит, серверу всё-таки шлётся реальный джид пользователя, а не room@conference.jabber.ru/nick". Так что я просто забрал остатки кода после этого комментария и сделал из него свою процедуру, выкинув ненужное. Также мне пришлось наприсать свою процедуру проверки на ошибку, основывающуюся на muc::test_error_res, потому что оригинальная меня не устраивала. Процедура отсылки бана вызывается один раз, если у нас команда /banjid (её я добавил позже, когда всё заработало), и в цикле, если команда — /bldjid. Вот, собственно, и всё.

Ну или почти всё. Плагин работает, но его можно чуть-чуть доделать. Сейчас он шлёт запросы на бан тупо во все комнаты, где я нахожусь. Но админю-то я не во всех. Это означает лишний трафик для меня и лишнюю нагрузку на сервер. Значит, мне надо как-то отфильтровать те комнаты, где я имею права админа. Тут, как может показаться, заколдованный круг: чтобы узнать, админю ли я в комнате, надо спросить у сервера. А это как раз лишний трафик и лишний пинок серверу. Но если подумать хорошо, то мы ведь уже знаем, что если я в ростере комнаты сижу в группе "Модераторы", то значит, и права тут имею модераторские. Так что надо проверить ростер каждой конференции и выбрать лишь нужные. Вот и обозначилось направление для поисков — найти, где рисуется ростер конференции, и выдрать оттуда нужный код :) На самом деле всё немного сложнее, потому что я могу быть не админом, а модератором — я буду находиться в группе модеров, но банить не смогу. Небольшие издержки, но соотношение "количество работы/результат" получается неплохое. Ещё потребуется добавить исключение комнат вида channel%irc.server1.ru@irc.server2.com, чтобы запросы не слались в комнаты, не поддерживающие стандарт MUC. Тут уже, скорее всего, придётся писать свой парсер.

Отладка

Спешка нужна лишь при ловле блох

При отлове багов торопиться не надо. Вот вы получили сообщение об ошибке. Прочитайте его внимательно: там дана практически вся необходимая для отладки информация. Если виной всему опечатка в имени команды или аргумента, так и будет сказано (имя команды не существует или что-то в этом духе). Если вы позабыли где-то скобку, об этом тоже будет сказано начистоту. Вам дадут ссылку на ошибку вплоть до седьмого колена: в какой строке какой процедуры, вызванной кем и откуда находится источник проблем.

(!) Сделать: Развить, если необходимо.

(!) Сделать: Вкратце написать про ::plugins::debug.

Консоль Ткаббера — наше всё

Она сэкономит вам уйму времени. Чтобы не перегружать Ткаббер после каждого изменения кода (а поначалу ошибки будут сыпаться как осенние листья, да и потом не факт, что код будет работать правильно и как вам бы хотелось), откройте консоль Ткаббера и напишите там:

source "/путь/содержащий пробелы/к/вашему/плагину/coolplugin.tcl"

Плагин должен не отходя от кассы загрузиться (при этом в консоли вам ничего не будет сказано, что говорит о положительном результате). Если в пути ошибка, консоль изругается. Всё, можно тестировать. Если вам кажется, что он не загрузился (не делает того, что от него ожидается), проверьте, существует ли его пространство имён:

namespace exists ::bldjid

Если ответ — 1, всё должно быть в порядке. Если 0, где-то косяки (в ДНК в коде, скорее всего — может, вы ошиблись в имени команды, и теперь Ткаббер "не узнаёт" то, что вы ему подсовываете; при этом, кстати, команда выведется в чате, как простое сообщение).

На первых порах очень неплохо быть в курсе того, что у вас попадает в переменные. Воспользуйтесь командой puts. Например, мы хотим узнать, действительно ли все конференции попали в список.

   foreach tmpchatid [lsort [lfilter chat::is_groupchat [chat::opened $xlib]]] {
       lappend groupjids [chat::get_jid $tmpchatid]
   }
   puts $groupjids

Результат действия этой команды будет выведен прямо в консоли. Ничто не мешает вам трассировать таким образом состояние переменных других скриптов Ткаббера. Просто добавьте печать нужной переменной в нужном месте, сохраните файл и не забудьте подгрузить его. Ещё одна удобная для тестирования команда — return stop. Если её поставить в вышеприведённом примере после puts, то дальнейшее выполнение кода прекратится. Полезно, когда сначала хочется отладить один кусок кода, не заморачиваясь на другом.

Внимание: Команда puts полезна, но не забудьте перед релизом их все убрать, иначе их вывод будет валиться в .xsession-errors пользователей плагина, что вряд ли кого-то обрадует.

Хоть консоль Ткаббера и является отличным отладочным инструментом, живого тестирования она заменить не может. Ваш покорный слуга погонял свой плагин, загруженный в Ткаббер через консоль, радостно выложил его сюда на вики, но когда через несколько дней дело дошло до реального масштабного бана, выскочила ошибка. В результате у автора плагина прибавилось ума, и он решил развить тему пространства имён (наверное, вы уже про это прочитали выше).

(!) Сделать: Рассказать про return -code break

Побольше тестируйте

Прежде чем выкладывать плагин на общее обозрение, погоняйте его самостоятельно. Проверьте его работу в нескольких версиях Ткаббера (svn и хотя бы одной-двух из последних стабильных) и на разных тиклях (8.5, 8.4 как минимум). Возможно, вы воткнули где-то команду, которая есть в одной версии языка или Ткаббера и нет в других. Решайте сами, что вам нужно: совместимость с ними или более продвинутый программинг/функциональность. В случае сомнений посоветуйтесь со знающими людьми. Скорее всего, можно и рыбку съесть, и на ёлку влезть, то есть, разрулить ситуацию так, что и совместимость не пострадает, и работать всё будет хорошо.

Пробуйте вводить нестандартные параметры, левые символы, и вообще создавать экстремальные условия для вашего скрипта. Например, для отсеивания каналов IRC я в проверочном условии использовал поиск вхождения в имя символа процента, поскольку такие комнаты работают через транспорт: somechannel%someserver.ru@irc.server.org. Однако потом я подумал (и это подтвердилось на практике), что и обычная MUC-комната может иметь знак процента в имени. Поэтому я доработал проверку таким образом:

   foreach tmpchatid [lsort [lfilter chat::is_groupchat [chat::opened $xlib]]] {
       set tmpgrp [chat::get_jid $tmpchatid]
       if {([lindex [bldjid::whoami $xlib $tmpgrp] 1] == "admin" \
       || [lindex [bldjid::whoami $xlib $tmpgrp] 1] == "owner") \
       && ![string match *%*@*irc* $tmpgrp]} {
           lappend groupjids $tmpgrp
       }
   }

Предполагается, что в имени транспорта обязательно должно присутствовать слово irc (иначе мы просто не догадаемся, что это IRC-транспорт), то есть, в теперешнем виде скрипт пропустит комнату mirc%room@conference.jabber.ru и не пропустит комнату channel%someserver.org@irc.putyourserverhere.ru. Кстати, скрипт в этом виде тормознёт и комнату mirc%room@conference.mirc.com (представим себе на мгновение, что на этом сайте есть джаббер-сервер), поэтому проверку следует изменить на *%*@irc* (точку после слова irc вылавливать не надо, на случай, если транспорт называется irctransport.server.org). Теперь максимум, что может случиться — если имя транспорта не начинается на "irc" (что очень маловероятно), то тогда, отправив запрос на бан в эту комнату, мы получим сообщение об ошибке.

Это лишь один пример. Напрягите фантазию, думайте за дурака-пользователя, предполагайте, что он может сморозить.

Научитесь пользоваться системой управления версиями

Не поленитесь поставить и освоить что-нибудь вроде subversion. Эта штука избавит вас от великой головной боли на тему "Блин, как уж я там позавчера эту хрень сделал? Сейчас бы мне этот кусок сюда, да потёр и не сохранил ту версию". Совсем не обязательно сходу просить допуск к репозиторию на xmpp.ru (особенно если у вас нет опыта работы с svn). Устройте себе локальный сервер: и от головной боли избавитесь, и работать с сабвершеном научитесь. Если вы считаете, что ваше творение должно находиться в общем репозитории svn.xmpp.ru, читайте дальше — там рассказано о его устройстве и о том, как получить к нему доступ. Врочем, ради одного плагина не стоит сильно заморачиваться. Выложите его на вики — делов-то.

(kostix замечает, что для локальной работы над проектом значительно удобнее Subversion использовать какого-нибудь представителя семейства распределённых систем управления версиями (DVCS), например, Bazaar, Mercurial, Git, Darcs, Monotone и т.п. — они позволяют лихо жонглировать кодом, не завися от центрального сервера.)

(bigote восторженно соглашается — не так давно освоенный им в минимальных количествах Git значительно упростил мышиную возню с кодом на десктопе. Но если вы планируете в конце концов поместить свой плагин в репозиторий tkabber-3rd-party-plugins, то лучше сразу вести разработку под svn или на крайний случай сделать это перед его публикацией туда, сначала экспортнув код из локального репозитория. Конечно, есть обвязки, позволяющие публиковать из git в svn, к примеру, но они не про нас, простых смертных начинающих плагинописателей ;). Вот, кстати, интересная притча (во всех переводах названная почему-то басней), простыми словами рассказывающая о мощи git.)

Тонкости

Здесь я попытаюсь рассказать о некоторых подводных камнях, на которые будет частенько находить ваша коса в процессе доведения плагина до ума. Моя, во всяком случае, на них натыкается преизрядно.

Хуки и return stop

Есть тонкая разница между командами return и return stop — первая не прерывает выполнения хука, если процедура, в которой она встретилась, является его обработчиком. Поясню на примере того же плагина Bldjid. Он разросся, и теперь там есть процедура smart_enter_exit_message, которая обрабатывает хук client_presence_hook (который срабатывает, когда кто-нибудь меняет своё состояние либо заходит в комнату). Я по незнанию понаставил в некоторые проверки внутри этой процедуры return stop вместо return, и в результате при определённых условиях перестал показываться ростер конференции, да и другие странности в работе Ткаббера появились. Дело было как раз в том, что вместо того, чтобы мирно завершить свою работу и отдать бразды правления другим обработчикам, эта процедура обрывала хук, и само собой, никто уже не заполнял ростер группы.

Сложно дать готовый рецепт на все случаи жизни, но можно посоветовать подходить с осторожностью к использованию return stop в обработчиках хуков. В обычных процедурах наоборот, лучше перестраховаться. Я только что попробовал позаменять все стопы на обычные return в теле простых процедур — результат плачевный: команды-то выполняются, но потом их текст выводится в общий чат, что нам совершенно не нужно.

Делаем плагин динамически подключаемым

С появлением в Ткаббере Менеджера плагинов жизнь пользователя стала намного проще. Чтобы подключить нужный плагин, достаточно сделать несколько кликов (Настройки → Plugins Management → отметить галочкой нужный плагин → сохранить настройку). Естественно, сам плагин перед этим всё равно должен быть помещён в соответствующее место, но согласитесь, что это значительный шаг вперёд, тем более, что, сняв эту галочку, плагин можно частично из памяти выгрузить. Почему частично? Не буду забегать вперёд, начну по порядку.

Добавляем в namespace код для запуска процедур загрузки и выгрузки

if {![::plugins::is_registered bldjid]} {
    ::plugins::register bldjid \
            -namespace [namespace current] \
            -source [info script] \
            -description [::msgcat::mc "Whether the Bldjid plugin is loaded."] \
            -loadcommand [namespace code load] \
            -unloadcommand [namespace code unload]
    return
}

Помещать его следует в самом начале неймспейса, но после строки ::msgcat::mcload [file join [file dirname [info script]] msgs], если таковая у вас имеется, иначе не загрузится локализованный текст пояснительной строчки. Как видите, тут всё просто. Вам надо только поменять слово bldjid на название вашего плагина (должно совпадать с именем его каталога).

Создаём эти самые процедуры загрузки и выгрузки

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

Процедура загрузки

Рассмотрим разбираемый в этой статье плагин Bldjid:

proc bldjid::load {} {
# A variable where the last query result is stored.
       variable user_list
# An array where all user entrances are stored.
       global jids_by_chats
       variable ent_cntr 1
       event add <<ToggleMonitor>> <Control-m>

       hook::add generate_completions_hook \
       [namespace current]::visitors_compls
       hook::add chat_send_message_hook \
       [namespace current]::handle_commands 17
       ::hook::add open_chat_post_hook [namespace current]::setup_bindings
       hook::add client_presence_hook \
       [namespace current]::smart_enter_exit_message 69
       hook::add room_nickname_changed_hook \
       [namespace current]::smart_enter_exit_message 51
}
Теперь о процедуре выгрузки
proc bldjid::unload {} {
       variable user_list
       global jids_by_chats
       variable ent_cntr
       event delete <<ToggleMonitor>> <Control-m>

       hook::remove generate_completions_hook \
       [namespace current]::visitors_compls
       hook::remove chat_send_message_hook \
       [namespace current]::handle_commands 17
       ::hook::remove open_chat_post_hook [namespace current]::setup_bindings
       hook::remove client_presence_hook \
       [namespace current]::smart_enter_exit_message 69
       hook::remove room_nickname_changed_hook \
       [namespace current]::smart_enter_exit_message 51

       catch {unset ent_cntr}
       catch {unset user_list}
       catch {unset jids_by_chats}

       foreach chatid [chat::opened] {
               clear_monitor $chatid
               set ccw [::chat::winid $chatid]
               if {![catch {pack info $ccw.mon} res]} {
                       pack forget $ccw.mon $ccw.vsb
               }
       }
}

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

Возможна ли полная выгрузка плагина из памяти?

На сегодняшний день выгрузка плагина из памяти ограничена лишь хуками, переменными и событиями, о чём я уже написал. Однако в памяти остаётся ещё немало:

Из беседы с разработчиками мне удалось узнать следующее (цитирую):

Так что если обозначить планы для дальнейших исследований, их можно свести к четырём рекомендациям:

  1. Изучить механизм custom::defvar и попробовать написать custom::противоположное_defvar.
  2. Если заниматься этим ломает, можно попробовать провести эксперимент: сделать namespace delete ::plugins::pluginname при живых переменных кастомайза и посмотреть, что получится; при этом подразумевается, что весь код плагина упрятан в его неймспейс;
  3. Если плагин создавал какие-то свои временные файлы на диске, не забывать удалять их при выгрузке (не путайте это с логами, которые создаются для пользователя! если ему надо будет их убить, он убьёт их сам).
  4. Не забывать про открытые окна и прочие ресурсы, создаваемые плагином — я уже показал, как делается проверка на предмет забытых окошек монитора; кроме того, вы можете изучить процедуры выгрузки игровых плагинов: chess, reversi и т. д. — если выключить плагин, когда открыта партия, её окно закроется (сначала плагин удаляет из памяти всю свою графику, как об этом уже было сказано выше).

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

Вот, собственно, и всё. Если у меня появятся результаты исследований описанных выше проблем, я непременно их здесь выложу. Призываю сделать то же самое и вас.

Не бойтесь задавать вопросы

Один вопрос специалисту сэкономил мне несколько часов напрасной работы. Камрад kostix подсказал мне простое решение проблемы, как узнать, в какой комнате я админю. А ещё через минуту и процедурку сваял:

proc whoami {xlib where} {
   set chatid [chat::chatid $xlib $where]
   set jid $where/[get_our_groupchat_nick $chatid]
   list $muc::users(role,$xlib,$jid) $muc::users(affiliation,$xlib,$jid)
}

Конечно, задавая вопросы, следует помнить о простых правилах, изложенных в этой статье. На всякий случай напомню основные:

Общие сведения о репозитории

Для разработки неофициальных проектов, имеющих отношение к Ткабберу (и в том числе — плагинов), был создан специальный репозиторий Subversion:

svn.xmpp.ru/repos/tkabber-3rd-party/

то есть он расположен "рядом" с официальным репозиторием Ткаббера и поддерживает такие же две схемы доступа: http и https.

Основная структура репозитория на данный момент такова:

svn.xmpp.ru/repos/tkabber-3rd-party/
  trunk/
    plugins/
  tags/
  branches/

то есть предполагается, что плагины будут складываться в

svn.xmpp.ru/repos/tkabber-3rd-party/trunk/plugins

а их "ветки" делаться где-то под

svn.xmpp.ru/repos/tkabber-3rd-party/branches/

Формат веток, в принципе, не важен. Например, юзер vasya может делать ветки в

 svn.xmpp.ru/repos/tkabber-3rd-party/branches/vasya/mycoolplugin/testing-stuff

а может — в

svn.xmpp.ru/repos/tkabber-3rd-party/branches/plugins/mycoolplugin/testing-other-stuff

Можно и весь "куст" под trunk'ом копировать под branchesветки в Subversion дёшевы и не зависят от формального объёма копируемой части дерева.

Идея состоит в том, чтобы не иметь "побочных" каталогов в каталогах с плагинами. Это позволит любому пользователю выполнить

svn co https://svn.xmpp.ru/repos/tkabber-3rd-party/trunk/plugins .

и получить себе полный набор "готовых к употреблению" плагинов.

Как получить доступ к репозиторию

  1. Заиметь некий готовый код или хотя бы внятную идею, которые можно будет предъявить в качестве доказательства стремления быть допущеным к репозиторию;
  2. Связаться с Kostix;
  3. Выбрать себе имя пользователя и пароль. Пароль можно сообщить "открытым текстом" (как есть) или сгенерировать на нём "хэш для htpasswd". Сие делается либо при помощи программы htpasswd из комплекта Web-сервера Apache путём запуска её в виде

    htpasswd -n USERNAME
    

    или при помощи этой Web-формы;

  4. Подождать, пока вас не допустят к телу репозитория, о чём Kostix вам сообщит;

  5. Сделать, к примеру,

    svn --username myusername mkdir https://svn.xmpp.ru/repos/tkabber-3rd-party/trunk/plugins/myplugin
    

    и убедиться в том, что репозиторий позволил вам сделать изменение в нём, то есть аккаунт создан правильно.

В заключение

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

Удачи вам! И ничего не бойтесь :)