Посібник розробника

If you ran the devinstall installation instructions, you have downloaded the sources, connected to the github repository. You are in the ideal situation to start looking into the software, understand how it works, contribute to ghini.desktop’s development.

Допомога в розвитку Ghini

Якщо ви хочете внести свій внесок у Ghini, ви можете зробити це кількома різними способами:

  • Використовуйте програмне забезпечення, відзначте те, що вам не подобається, відкрийте проблему <http://github.com/Ghini/ghini.desktop/issues/new> _ для кожної з них. Розробник буде реагувати швидше, ніж ви можете собі уявити.
  • Якщо у вас є ідея про те, що пропущено в програмному забезпеченні, але не можете повністю формалізувати її в окремі питання, ви можете розглянути питання про наймання професіонала. Це найкращий спосіб переконатися, що щось відбувається швидко на Ghini. Переконайтеся, що розробник відкриває проблеми та публікує їхній внесок у github.
  • Перекласти! Будь-яка допомога з перекладом буде прийнята, тому, будь ласка, будь ласка! Ви можете це зробити, не встановлюючи нічого на своєму комп’ютері, просто скористайтеся службою перекладів онлайн, яку пропонує http://hosted.weblate.org/
  • виділіть репозиторій, виберіть проблему, вирішіть її, відкрийте запит зняти. Дивіться bug solving workflow нижче.

Якщо ви ще не встановили Ghini і хочете поглянути його історію кодів, ви можете відкрити нашу `github сторінку проєкту <http://github.com/Ghini/ghini.desktop>`_і побачити все, що відбувалося навколо Ghini з моменту його створення, як в Bauble, ще в 2004 році.

If you install the software according to the devinstall instructions, you have the whole history in your local git clone.

Джерело програмного забезпечення, версії, розширення

Якщо ви хочете отримати певну версію Ghini, ми випускаємо та підтримуємо версії як розширення. Ви повинні `` git checkout`` розширення, яку відповідає вибраній вами версії.

виробнича лінія

Назва розширень для стабільних (виробничих) версій Ghini складається з форми ghini-x.y (наприклад: ghini-1.0); імена розширень, у яких публікуються тестові версії Ghini, мають форму ghini-x.y-dev (наприклад, ghini-1.0-dev).

Процес розробки

Наш робочий процес полягає в тому, щоб постійно займатися тестуванням розширень, часто поширювати їх на github, щоб дозволити travis-ci та coveralls.io перевірити якість тестовних розширень, нарешті, час від часу, об’єднати тестовані розширення у відповідну версію.

Під час роботи над складними проблемами, які тривають більше двох днів, я можу відкрити філію, пов’язану з цією проблемою. Я не роблю це дуже часто.

більше питань

Коли постали перед однією складною проблемою, створіть тег відгалуження на кінці основної лінії розробки (наприклад, ghini-1.0-dev) і дотримуйтесь робочого процесу, описаного в

https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging

коротко:

git up
git checkout -b issue-xxxx
git push origin issue-xxxx

Працюйте в новій тимчасовій гілці. По готовності, перейдіть на github, з’єднайте гілку з основною лінією розвитку, з якої ви розгалужені, вирішіть конфлікти у разі потреби, видаліть тимчасову гілку.

Коли ви готові до публікації, об’єднайте лінію розвитку в відповідну виробничу лінію.

Оновлення установки перекладних рядків

Час від часу під час оновлення програмного забезпечення ви будете додавати або змінювати рядки в джерелах python, в документації, в glade джерелах. Більшість наших рядків є перекладами, і пропонуються weblate для людей, щоб зробити внесок у формі декількох .po файлів.

В основному po складається з пар текстових частин, оригінал і переклад і є специфічним для цільової мови. Коли перекладач додає переклад на weblate, це потрапляє до нашого сховища на github. Коли програміст додає рядок до програмного забезпечення, це досягає weblate «для перекладу».

Weblate хост Ghini проєкт. У рамках цього проєкту ми маємо компоненти, кожен з яких відповідає гілці сховища на github. Кожен компонент приймає переклад на декількох мовах.

компонент сховище гілка
Desktop 1.0 ghini.desktop ghini-1.0-dev
Desktop 3.1 ghini.desktop ghini-3.1-dev
Documentation 1.0 ghini.desktop-docs.i18n ghini-1.0-dev
Documentation 3.1 ghini.desktop-docs.i18n ghini-3.1-dev
Web 1.2 ghini.web master
Pocket ghini.pocket master
Tour ghini.tour master

Щоб оновити файли po відносно програмного забезпечення, встановіть робочий каталог у корінь вашої копії ghini.desktop і запустіть скрипт:

./scripts/i18n.sh

Щоб оновити po файли документації, встановіть робочий каталог у корінь вашої копії ghini.desktop-docs.i18n, і запустіть скрипт:

./doc/runme.sh

Коли ви запускаєте будь-який з вищезазначених сценаріїв, швидше за все, вам потрібно фіксувати all ``po``файли в проєкті. Ви можете переглянути зміни, перш ніж застосувати їх до репозиторію. Це найголовніше коли ви виконуєте критичну корекцію до рядка, наприклад видалення помилки.

Те, що відбувається: вступ у конфлікт. Вирішити конфлікти не складно, коли ви знаєте, як це зробити. Перш за все, додати weblate як віддалений:

git remote add weblate-doc10 https://hosted.weblate.org/git/ghini/documentation-10/

Потім переконайтеся, що ми знаходимося в правильному сховищі, на правильній гілці, оновіть дистанційне керування, злийте з ним:

git checkout ghini-1.0-dev
git remote update
git merge weblate-doc10/ghini-1.0-dev

Our documentation на readtodocs є оригінальна англійська версія, і кілька перекладів. Ми просто дотримуємося description of localisation, немає нічого, що ми винайшли собі тут.

Readthedocs перевіряє налаштування проєкту Language, і викликає sphinx-intl``для отримання відформатованої документації на цільовій мові. З конфігурацією за замовчуванням —що ми не змінювали— ``sphinx-intl очікує один po файл на один вихідний документ, названий як вихідний документ і що всі вони перебувають у каталозі local/$(LANG)/LC_MESSAGES/.

З іншого боку, Weblate (і ми самі) віддає перевагу одному po файлу на кожну мову, і зберігаємо їх всіх у однакових директоріях / po, подібно тому, як ми робимо для програмного проєкту: /po/$(LANG).po.

Щоб не повторювати інформацію, і дозволити обом системам працювати природним способом, у нас є два набори символічних посилань (git визначає їх).

Підбиваючи підсумок: коли файл у документації оновлюється, runme.sh скрипт буде:

  1. скопіюйте rst файли з програмного забезпечення в документацію;
  2. Створіть новий pot файл для кожного з файлів документації;
  3. об’єднайте всі pot файли в один doc.pot;
  4. використовуйте оновлений doc.pot для оновлення всіх файлів doc.po (по одному на кожну мову);
  5. створити всі символічні посилання:
    1. ті, що очікуються sphinx-intl в /local/$(LANG)/LC_MESSAGES/
    2. ті, що використовуються weblate в /po/$(LANG).po

Ми могли б напевно записати вищевказане в Makefile, або навіть краще включити його в /doc/Makefile. Хто знає, може, ми це зробимо.

Producing the docs locally

The above description is about how we help external sites produce our documentation so that it is online for all to see. But what if you want to have the documentation locally, for example if you want to edit and review before pushing your commits to the cloud?

In order to run sphinx locally, you need to install it within the same virtual environment as ghini, and to install it there, you need to have a sphinx version whose dependencies don not conflict with ghini.desktop’s dependecies.

What we do to keep this in order?

We state this extra dependency in the setup.py file, as an extras_require entry. Create and activate the virtual environment, then run easy_install ghini.desktop[docs]. This gets you the sphinx version as declared in the setup.py file.

If all you want is the html documentation built locally, run ./setup.py install docs. For more options, enter the doc directory and run make.

Яким чином перекладені рядки досягають наших користувачів?

Новий перекладач поставив запитання, додавши: «Чи це автоматичний процес від Weblate –> GIT –> Ghini Desktop встановлений на комп’ютерах користувачів, чи це вимагає ручних кроків?

Вважається, що вся взаємодія досить складна, і це залежить від компонента.

When you install ghini.desktop or one of the Android apps, the installation doesn’t assume a specific run-time language: a user can change their language configuration any time. So what we do is to install the software in English together with a translation table from English to whatever else.

At run-time the GUI libraries (Android or GTK) know where to look for the translation strings. These translation tables are generated during the installation or upgrade process, based on the strings you see on Weblate.

The path followed by translations is: You edit strings on Weblate, Weblate keeps accumulating them until you are done, or you don’t interact with Weblate for a longer while; Weblate pushes the strings to github, directly into the development line ghini-1.0-dev; I see them and I might blindly trust or prefer to review them, maybe I look them up in wikipedia or get them translated back to Italian, Spanish or English by some automatic translation service; sometimes I need to solve conflicts arising because of changed context, not too often fortunately. As said, this lands in the development line ghini-1.0-dev, which I regularly publish to the production line ghini-1.0, and this is the moment when the new translations finally make it to the distributed software.

Users will notice a new version available warning and can decide to ignore it, or to update.

For ghini.pocket, it is similar, but the notification is handled by the Android system. We publish on the Play Store, and depending on your settings, your phone will update the software automatically, or only notify you, or do nothing. It depends on how you configured automatic updates.

Для ghini.web ми ще не визначили, як його розповсюджувати.

Для документації ghini вона повністю автоматична, і все це обробляється readthedocs.org.

Додавання відсутніх одиничних тестів

Якщо ви зацікавлені в сприянні розвитку Ghini, хороший спосіб зробити це буде, допомагаючи нам знаходити та писати пропущені тестові блоки.

Добре перевіреною функцією є та, чия поведінка не може змінюватися, не порушуючи принаймні одне тестування.

Ми всі погоджуємося, що в теорії теорія та практика ідеально узгоджуються, і що спочатку пишуть тести, потім реалізують функцію. На практиці, однак, практика не збігається з теорією, і ми писали тести після написання та навіть публікації функцій.

Цей розділ описує процес додавання одиночних тестів для bauble.plugins.plants.family.remove_callback.

Що для тесту

Перш за все, відкрийте індекс звіту про охоплення та виберіть файл з низьким рівнем охоплення.

Для цього прикладу, починаючи з жовтня 2015 року, ми приземлилися на bauble.plugins.plants.family, на 33%.

https://coveralls.io/builds/3741152/source?filename=bauble%2Fplugins%2Fplants%2Ffamily.py

Перші дві функції, які потребують тестів, edit_callback і add_genera_callback, включають створення та активацію об’єкта, що спирається на спеціальне діалогове вікно. Ми повинні спочатку написати одиничні тести для цього класу, а потім повернутися сюди.

Наступна функція remove_callback також активує пару діалогових вікон і повідомлень, але у формі виклику функції, що запитує вхід користувача через поля yes-no-ok. Ці функції ми можемо легко замінити функцією, що висміює поведінку.

як протестувати

Отже, вирішивши, що описувати в одиничному тесті, ми розглянемо код, і бачимо, що це потребує дискримінації пари випадків:

** коректність параметра **
  • у списку сімей немає елементів.
  • список сімей містить більше одного елемента.
  • список сімей має рівно один елемент.
каскад
  • у сім’ї немає родів
  • у сім’ї один чи більше родів
підтвердити
  • користувач підтверджує видалення
  • користувач не підтверджує видалення
видалення
  • при видаленні сім’ї все пройшло добре
  • під час видалення сім’ї виникає помилка

Я вирішу зосередитись лише на аспектах каскад і підтвердити. Два бінарних питання: 4 випадки.

де поставити тести

Знайдіть тестовий скрипт і виберіть клас, де слід поставити додаткові одиничні тести.

https://coveralls.io/builds/3741152/source?filename=bauble%2Fplugins%2Fplants%2Ftest.py#L273

що про пропущені тести

Клас FamilyTests містить пропущене тестування, і його реалізація займе дещо час, тому що нам потрібно переписати FamilyEditorPresenter, відокремити його від FamilyEditorView і переглянути, що робити з класом FamilyEditor, який, на мою думку, повинен бути вилучений і замінений однією функцією.

написання тестів

Після останнього тесту в класі FamilyTests я додаю чотири випадки, які я хочу описати, і я переконаний, що вони завершаться невдачею, і оскільки я ледачий, я пишу найбільш компактний код, який я знаю, для генерації помилки:

def test_remove_callback_no_genera_no_confirm(self):
    1/0

def test_remove_callback_no_genera_confirm(self):
    1/0

def test_remove_callback_with_genera_no_confirm(self):
    1/0

def test_remove_callback_with_genera_confirm(self):
    1/0

Один тест, крок за кроком

Почнемо з першого тесту.

Під час написання тестів я зазвичай дотримуюсь зразка:

  • T₀ (початковий стан),
  • дія,
  • T₁ (тестування результату дії з урахуванням початкових умов)

що в імені - одиничні тести

Є причина, чому одиничні тести називаються одиничними тестами. Будь-ласка, ніколи не перевіряйте дві дії в одному тесті.

Тож давайте опишемо T₀ для першого тесту, бази даних, що містить родину без родів:

def test_remove_callback_no_genera_no_confirm(self):
    f5 = Family(family=u'Arecaceae')
    self.session.add(f5)
    self.session.flush()

Ми не хочемо, щоб тестована функція викликала інтерактивну функцію utils.yes_no_dialog, а хочемо викликати неінтерактивну функцію заміни remove_callback. Ми досягаємо цього просто, зробивши вираз utils.yes_no_dialog виразом lambda, який, як і початкова інтерактивна функція, приймає один параметр і повертає логічний. У цьому випадку: False:

def test_remove_callback_no_genera_no_confirm(self):
    # T_0
    f5 = Family(family=u'Arecaceae')
    self.session.add(f5)
    self.session.flush()

    # action
    utils.yes_no_dialog = lambda x: False
    from bauble.plugins.plants.family import remove_callback
    remove_callback(f5)

Далі ми перевіряємо результат.

Що ж, ми не хочемо просто перевірити, чи був об’єкт Arecaceae видалений, чи ні, ми також повинні перевірити значення, яке повертає remove_callback, і чи yes_no_dialog і `` message_details_dialog`` були викликані чи ні .

Для цього не вистачає виразу lambda. Ми робимо щось набагато складніше, що зробить життя набагато простіше.

Давайте спочатку визначимо досить загальну функцію:

def mockfunc(msg=None, name=None, caller=None, result=None):
    caller.invoked.append((name, msg))
    return result

і ми захоплюємо partial з стандартного модуля functools, частково застосувати вищенаведене `` mockfunc``, залишивши тільки msg невизначеним, і використовуйте цю часткову програму, яка є функцією, що приймає один параметр і повертає значення, замінити дві функції в utils. Тестова функція тепер виглядає так:

def test_remove_callback_no_genera_no_confirm(self):
    # T_0
    f5 = Family(family=u'Arecaceae')
    self.session.add(f5)
    self.session.flush()
    self.invoked = []

    # action
    utils.yes_no_dialog = partial(
        mockfunc, name='yes_no_dialog', caller=self, result=False)
    utils.message_details_dialog = partial(
        mockfunc, name='message_details_dialog', caller=self)
    from bauble.plugins.plants.family import remove_callback
    result = remove_callback([f5])
    self.session.flush()

Тестовий розділ перевіряє, що message_details_dialog` не було викликано, що yes_no_dialog було викликано, з правильним параметром повідомлення, що Arecaceae все ще існує:

# effect
self.assertFalse('message_details_dialog' in
                 [f for (f, m) in self.invoked])
self.assertTrue(('yes_no_dialog', u'Are you sure you want to '
                 'remove the family <i>Arecaceae</i>?')
                in self.invoked)
self.assertEquals(result, None)
q = self.session.query(Family).filter_by(family=u"Arecaceae")
matching = q.all()
self.assertEquals(matching, [f5])

І так далі

„Є два види людей, ті, хто завершує те, що вони починають, і так далі“

Наступне тестування майже однакове, з тією різницею, що utils.yes_no_dialog повинен повертати True (це ми досягаємо, вказавши result = True в частковому застосуванні загальної форми mockfunc `).

За допомогою цієї дії значення, яке повертає remove_callback, має бути True, і не повинно більше бути сім’ї Arecaceae в базі даних:

def test_remove_callback_no_genera_confirm(self):
    # T_0
    f5 = Family(family=u'Arecaceae')
    self.session.add(f5)
    self.session.flush()
    self.invoked = []

    # action
    utils.yes_no_dialog = partial(
        mockfunc, name='yes_no_dialog', caller=self, result=True)
    utils.message_details_dialog = partial(
        mockfunc, name='message_details_dialog', caller=self)
    from bauble.plugins.plants.family import remove_callback
    result = remove_callback([f5])
    self.session.flush()

    # effect
    self.assertFalse('message_details_dialog' in
                     [f for (f, m) in self.invoked])
    self.assertTrue(('yes_no_dialog', u'Are you sure you want to '
                     'remove the family <i>Arecaceae</i>?')
                    in self.invoked)
    self.assertEquals(result, True)
    q = self.session.query(Family).filter_by(family=u"Arecaceae")
    matching = q.all()
    self.assertEquals(matching, [])

подивіться на commit 734f5bb9fffc2f4bd22578fcee1802c8682ca83 для двох інших тестових функцій.

Реєстрація тестування

Наші об’єкти bauble.test.BaubleTestCase використовують обробники класу bauble.test.MockLoggingHandler. Кожен раз, коли починається індивідуальне тестування, метод setUp створить новий handler І пов’язати його з кореневим реєстратором. Метод tearDown дбає про його видалення.

Ви можете перевірити присутність конкретних повідомлень журналу в `` self.handler.messages``. `` Messages`` - словник, спочатку порожній, з двома рівнями індексації. По-перше, ім’я реєстратора, який видає журнал реєстрації, потім ім’я рівня запису журналу. Ключі створюються, коли це необхідно. Значення містить списки повідомлень, відформатовані за будь-яким форматом, який ви зв’язуєте з обробником, за умовчанням для logging.Formatter ("%(message)s").

Ви можете явним чином порожнім зібраним повідомленням викликати self.handler.clear().

Введення всіх разом

Час від часу ви хочете активізувати тестовий клас, з яким ви працюєте:

nosetests bauble/plugins/plants/test.py:FamilyTests

І в кінці процесу ви хочете оновити статистику:

./scripts/update-coverage.sh

Структура користувацького інтерфейсу

Інтерфейс користувача побудований відповідно до архітектурного шаблону ModelViewPresenter. Для більшості інтерфейсів Model є об’єктом бази даних SQLAlchemy, але у нас також є елементи інтерфейсу, де немає відповідної моделі бази даних. В загальному:

  • View описується як частина файлу glade. Це повинно включати асоціації зворотного виклику сигналу та ListStore-TreeView. Просто повторно використовуйте базовий клас GenericEditorView, визначений у bauble.editor. Коли ви створюєте екземпляр цього загальнодоступного класу, передайте його назву файлу glade та ім’я root-віджет, а потім передайте цей екземпляр класу конструктору presenter.

    У файлі поля, у розділі action-widgets, що закриває опис об’єкта GtkDialog, переконайтеся, що кожен елемент action-widget має дійсне response значення. Використовуйте дійсні значення GtkResponseType, наприклад:

    • GTK_RESPONSE_OK, -5
    • GTK_RESPONSE_CANCEL, -6
    • GTK_RESPONSE_YES, -8
    • GTK_RESPONSE_NO, -9

    Існує непростий спосіб об’єднати тестування представленням підкласу, тому, будь ласка, не переглядайте підклас, там насправді немає потреби.

    У файлі поля, кожен вхідний віджет повинен визначити, який обробник активується на який сигнал. Загальний клас Presenter пропонує загальні зворотні виклики, які охоплюють найбільш поширені випадки.

    • GtkEntry (однорядкове введення) буде обробляти сигнал changed, з будь-яким on_text_entry_changed або on_unique_text_entry_changed.
    • GtkTextView: пов’язати його з GtkTextBuffer. Для обробки сигналу changed на GtkTextBuffer, ми повинні визначити обробник, який викликає загальний on_textbuffer_changed, єдина роль для цієї функції полягає в тому, щоб передати нашому загальному обробнику ім’я атрибуту моделі, який отримує зміну. Це робочий апарат для невирішеної помилки в GTK.
    • GtkComboBox з перекладеними текстами не може бути легко оброблено з glade файлу, тому ми навіть не намагаємося. Використовуйте метод init_translatable_combo загального класу GenericEditorView, але будь ласка, введіть його з **presenter **.
  • Model - це лише об’єкт з відомими атрибутами. У цій взаємодії model є просто пасивним контейнером даних, це не більше, ніж дозволити presenter змінити це.

  • Підклас Presenter визначає та реалізує:

    • widget_to_field_map, словник, що пов’язує імена віджетів з назвою атрибутів моделі,
    • view_accept_buttons, список імен віджетів, які, якщо вони активуються користувачем, означають, що вигляд повинен бути закритий,
    • всі необхідні зворотні виклики,
    • за бажанням, це також відтворює model.

    presenter постійно оновлює model відповідно до змін у view. Якщо model відповідає об’єкту бази даних, presenter зобов’язує всі model оновити базу даних, коли view успішно закрито або повертається назад, якщо view скасовано (ця поведінку залежить від параметра do_commit)

    Якщо model є чимось іншим, то presenter зробить щось інше.

    Примітка

    Хороша поведінка presenter використовує view api, щоб запитати значення, вставлені користувачем, або насильно встановити статуси віджетів. Будь ласка, не використовуйте практики наших невірних ведучих, деякі з яких безпосередньо обробляють поля „view.widgets“. Таким чином, ведучі перешкоджають нам створити одиничні тести.

Базовий клас для ведучого, GenericEditorPresenter, визначений у bauble.editor, реалізує багато корисних загальних зворотних викликів. Існує клас MockView, який ви можете використовувати при написанні тестів для своїх ведучих.

Приклади

Contact та ContactPresenter реалізуються за наведеними вище рядками. Вид визначається у файлі contact.glade.

Хорошим приклад шаблону Presenter/View (без model) надає менеджер з’єднань.

Ми використовуємо той самий архітектурний шаблон для взаємодії, що не пов’язаний з базою даних, шляхом встановлення ведучого також як модель. Ми робимо це, наприклад, для діалогового вікна експорту JSON. Наступна команда дасть вам список GenericEditorView інстанцій:

grep -nHr -e GenericEditorView\( bauble

Розширення Ghini з плагінами

Майже все Ghini розширюється за допомогою плагінів. Плагіни можуть створювати таблиці, визначати власні пошукові запити, додавати пункти меню, створювати власні команди та багато іншого.

Щоб створити новий плагін вам необхідно розширити bauble.pluginmgr.Plugin клас.

Плагін Tag є гарним мінімальним прикладом, навіть якщо TagItemGUI виходить за рамки моделі архітектури Model-View-Presenter.

Структура плагінів

Ghini є основою для обробки колекцій, і поширюється разом із набором плагінів, що робить Ghini ботанічним менеджером збору. Але Ghini залишається рамкою, і ви могли б теоретично видалити всі плагіни, які ми поширюємо та пишемо власноруч, або напишіть свої власні плагіни, які розширять чи завершать поточну поведінку Ghini.

Після того як ви вибрали та відкрили з’єднання з базою даних, ви виходите в вікно пошуку. Вікно пошуку - це взаємодія між двома об’єктами: SearchPresenter (SP) та SearchView (SV).

SV - це те, що ви бачите, SP зберігає стан програми та обробляє запити, які ви висловлюєте через SV. Обробка цих запитів впливає на вміст SV та статус програми в SP.

Результати пошуку, відображені у більшій частині SV, є рядками, об’єктами, що є класами, зареєстрованими у плагіні.

Кожне з цих класів повинно реалізовувати певну кількість функцій, щоб правильно поводитися в рамці Ghini. Система Ghini зберігає простір для підключених класів.

SP знає всі зареєстровані (підключені) класи, вони зберігаються в словнику, асоціюючи клас із його реалізацією плагінів. SV має слот (gtk.Box), де ви можете додати елементи. У будь-який час, максимум лише один елемент у слоті видно.

Плагін визначає один або кілька класів плагінів. Клас плагіна відіграє роль часткового ведучого (pP - плагін-ведучий), оскільки він реалізує зворотні виклики, необхідні для відповідного приєднання часткового вигляду в слоті (pV-plugin view), а шаблон MVP завершується батьківським ведучим (SP ), знову діючи як модель. Підсумувати і завершити:

  • SP виступає як модель,
  • частковий вигляд pV визначається у glade файлі.
  • зворотні зв’язки, реалізовані за допомогою pP, посилаються на glade файл.
  • контекстне меню для рядка SP,
  • дочірні власності.

коли ви реєструєте клас плагіна, SP:

  • додає pV в слот і робить його невидимим.
  • додає екземпляр pP у зареєстровані класи плагінів.
  • повідомляє pP, що SP є моделлю.
  • з’єднує всі виклики від pV до pP.

коли елемент у тригерах pV викликає дію в pP, pP може передати дію SP і може запитати SP, що він оновлює модель та оновлює представлення даних.

Коли користувач вибирає рядок в SP, SP ховає все в сполученому слоті і показує лише один pV відносно типу вибраного рядка, і запитує pP, щоб оновити pV з будь-яким параметром відносно вибраного рядка.

Окрім встановлення видимості різних pV, нічого не потрібно відключати чи видаляти: невидиме pv не може викликати події!

робочий процес над помилками

нормальний робочий процес розробки

  • під час користування програмним забезпеченням, ви помічаєте проблеми, або ви отримаєте уявлення про те, що може бути краще, ви думаєте про це, достатньо для того, щоб мати дуже чітке уявлення про це. Ви відкриваєте випуск і описуєте проблему. Хтось може реагувати на це.
  • ви відкриваєте сайт випусків і вибираєте один який ви хочете вирішувати.
  • призначити цей випуск для себе, таким чином, ви інформуєте спільноту, що у вас є намір працювати над ним.
  • за потреби, розгалуження сховища у вашому обліковому записі бажано створити гілку, безспірно пов’язану до випуску.
  • написати одиничні тести і передати їх у свою гілку (не надавайте несправні тести на github, спочатку запустіть nosetests).
  • написати додатковий блок тестів (в ідеалі, тести утворюють повний опис функції, ви це додаєте або коректуєте).
  • переконайтеся, що функція, яку ви додаєте або коректуєте дійсно повністю описує блок тестів, які ви написали.
  • переконайтеся, що блок тестів є простим, тобто, що ви тестуєте варіації змін по одній змінній. не додають введення складних для блоку тестів або тестів які не поміщаються на одному екрані (25 рядків в коді).
  • написати код, який робить тести успішними.
  • оновити файли i18n (запустити ./scripts/i18n.sh).
  • всякий раз, коли це можливо, переведіть нові рядки які ви вставляєте в код або glade файли.
  • коли ви змінюєте рядки, переконайтеся, що старі переклади повторно використовуються.
  • зафіксувати зміни.
  • передати github.
  • відкрити пул запиту.

публікація продукту

please use the publish.sh script, in the scritps directory. This one takes care of every single step, and produces recognizable commit comments, it publishes the release on pypi, and in perspective it will contain all steps for producing a deb file, and a windows executable.

Ви також можете це зробити вручну:

  • відкрийте сторінку запиту, використовуючи як основу виробничу лінію ghini-x.y у порівнянні з ghini-x.y-dev.
  • переконайтеся що bump фіксація включена в розбіжностях.
  • повинна бути забезпечена можливість автоматичного злиття гілок.
  • створити новий пул запиту, викличте його як “publish to the production line”.
  • вам, можливо, буде потрібно почекати travis-ci для виконання перевірки.
  • об’єднати зміни.

не забудьте розповісти світові про новий випуск: на facebook <https://www.facebook.com/bauble.thesoftware/>`_, the google group, у будь-якій відповідній пов’язаній групі на нашій веб-сторінці <http://ghini.github.io/>`_.

ваша власна гілка

Якщо ви хочете зберегти власну гілку проєкту, майте на увазі, що це робота в повну силу над результатом, і щоб бути в курсі, потрібні певні зусилля з вашої сторони.

Найкращий спосіб зберегти власну гілку полягає в тому, щоб сфокусуватися на певній конкретній проблемі, часто відкривають тягові запити для вашої роботи, переконайтеся, що ви це приймаєте. Просто дотримуйтесь стилю кодування Ghini, пишіть одиничні тести, лаконічні та ясні, і не повинно бути ніяких проблем в тому, щоб ваша робота була включена до Ghini.

Якщо гілка вийшла з синхронізації з Ghini вгору: читати, зрозуміти, слідкувати за github довідниками configuring a remote for a fork і syncing a fork.

крок закриття

  • розглянути цей робочий процес. розглядати це в якості орієнтира, до себе і до своїх колег. будь ласка, допоможіть зробити його краще і відповідно практичним.

Distributing ghini.desktop

Python Package Index - PyPI

This is not much mentioned, but we keep ghini.desktop on the Python Package Index, so you could install it by no more than:

pip install ghini.desktop

There are a couple packages that can’t be installed with pip, but otherwise that’s really all you need to type, and it’s platform independent.

Publishing on PyPI is a standard setup command:

python setup.py sdist --formats zip upload -r pypi

Windows

For building a Windows installer or executable you need a running Windows system. The methods described here has been used successfully on Windows 7, 8 and 10. Windows Vista should also work but has not been tested.

If you are on GNU/Linux, or on OSX, you are not interested in the remainder of this section. None of Ghini’s contributors knows how to produce a Windows installer without having a Windows system.

The goal of the present instructions is to help you produce a Windows installer, that is a single executable that you can run on any Windows workstation and that will install a specific version of ghini.desktop. This is achieved with the NSIS script-driven installer authoring tool.

As a side product of the installer production, you will have a massive but relocatable directory, which you can copy to a USB drive and which will let you use the software without needing an installation.

The files and directories relevant to this section:

  • scripts/build-win.bat — the single batch script to run.
  • setup.py — implements the NSIS and py2exe commands.
  • scripts/build-multiuser.nsi — the nsis script, used by the above.
  • nsis/ — contains redistributable NSIS files, put here for conveniency.
  • ghini-runtime/ — built by py2exe, used by nsis.
  • dist/ — receives the executable installation file.

Most steps are automated in the build-win.bat script. Installation of a few tools needs to be done manually:

  1. Download and install Git, Python 2.7 and PyGTK.

    This is outlined in the devinstall-based installation instructions.

  2. Download and install NSIS v3.

  3. Рекомендується перезавантажити.

  4. Clone the ghini.desktop repository.

    Use your own fork if you plan contributing patches, or the organization’s repository https://github.com/Ghini/ghini.desktop.git if you only wish to follow development.

    Clone the repository from GitHub to wherever you want to keep it, and checkout a branch. Replace <path-to-keep-ghini> with the path of your choice, e.g. Local\github\Ghini\. Production branch ghini-1.0 is recommended as used in the example.

    To do this, open a command prompt and type these commands:

    cd <path-to-keep-ghini>
    git clone <ghini.desktop repository URL>
    cd ghini.desktop
    git checkout ghini-1.0
    

The result of the above is a complete development environment, on Windows, with NSIS. Use it to follow development, or to propose your pull requests, and to build Windows installers.

All subsequent steps are automated in the scripts\build_win.bat script. Run it, and after a couple of minutes you should have a new dist\ghini.desktop-<version>-setup.exe file, and a working, complete relocatable directory named ghini-runtime.

Read the rest if you need details about the way the script works.

The build_win.bat script

Доступний пакетний файл, який може завершити останні кілька кроків. Для його використання скористайтеся цією командою:

scripts\build_win.bat

build_win.bat приймає 2 аргументи:

  1. /e — executable only.

    Produce an executable only, skipping the extra step of building an installer, and will copy win_gtk.bat into place.

  2. venv_path — A path to the location for the virtual environment to use.

    Defaults to "%HOMEDRIVE%%HOMEPATH%"\.virtualenvs\%CHECKOUT%-exe, where CHECKOUT corresponds to the name of the branch you checked out.

If you want to produce an executable only and use a virtual environment in a folder beside where you have ghini.desktop, you could execute scripts\build_win.bat /e ..\ghi2exe

py2exe не буде працювати з eggs

Створення виконуваного файлу Windows із py2exe вимагає встановлення пакетів ** не** як eggs. Для цього є кілька методів, зокрема:

  • Install using pip. The easiest method is to install into a virtual environment that doesn’t currently have any modules installed as eggs using pip install . as described below. If you do wish to install over the top of an install with eggs (e.g. the environment created by devinstall.bat) you can try pip install -I . but your mileage may vary.

  • Додавши:

    [easy_install]
    zip_ok = False
    

    до setup.cfg (або аналогічним чином zip_safe = False до setuptools.setup() в setup.py) можна використовувати python setup.py install, але вам необхідно завантажити та встановити `Microsoft Visual C++ Compiler для Python 2.7 <http://aka.ms/vcpython27>`_щоб отримати будь-яке розширення C, і йому буде потрібно свіже віртуальне середовище без залежних пакетів, встановлених як eggs.

The included build-win script uses the pip method.

installing virtualenv and working with environments

Install virtualenv, create a virtual environment and activate it.

With only Python 2.7 on your system (where <path-to-venv> is the path to where you wish to keep the virtual environment) use:

pip install virtualenv
virtualenv --system-site-packages <path-to-venv>
call <path-to-venv>\Scripts\activate.bat

On systems where Python 3 is also installed you may need to either call pip and virtualenv with absolute paths, e.g. C:\Python27\Scripts\pip or use the Python launcher e.g. py -2.7 -m pip (run python --version first to check. If you get anything other than version 2.7 you’ll need to use one of these methods.)

Populate the virtual environment

Встановити залежності та ghini.desktop у віртуальне середовище:

pip install psycopg2 Pygments py2exe_py2
pip install .

Compile for Windows

Створіть виконуваний файл:

python setup.py py2exe

The ghini-runtime folder will now contain a full working copy of the software in a frozen, self contained state.

This folder is what is packaged by NSIS.

This same folder can also be transferred however you like and will work in place. (e.g. placed on a USB flash drive for demonstration purposes or copied manually to C:\Program Files with a shortcut created on the desktop). To start ghini.desktop double click ghini.exe in explorer (or create a shortcut to it).

Fixing paths to GTK components.

If you run the relocatable compiled program, unpackaged, you might occasionally have trouble with the GUI not displaying correctly.

Should this happen, you need to set up paths to the GTK components correctly. You can do this by running the win_gtk.bat, from the ghini-runtime folder.

You will only need to run this once each time the location of the folder changes. Thereafter ghini.exe will run as expected.

Finally, invoke NSIS

Створіть встановлювач:

python setup.py nsis

This should leave a file named ghini.desktop-<version>-setup.exe in the dist folder. This is your Windows installer.

про програму установки

  • Можливість однокористувацької або глобальної інсталяції.

  • На даний момент ghini.desktop, встановлений таким чином, що не буде перевіряти або повідомляти вам про оновлену версію. Вам потрібно буде перевірити це самому.

  • Можливість завантаження та встановлення необов’язкових додаткових компонентів:

    • Apache FOP - Якщо ви хочете використовувати шаблони звітів xslt, встановіть FOP. FOP вимагає Java Runtime. Якщо у вас цього не встановлено, програма установки повідомить вас і запропонує відкрити веб-сайт Oracle для завантаження та встановлення з нього.
    • MS Visual C runtime - Ви, швидше за все, цього не потребуєте, але якщо у вас виникли проблеми з запуском ghini.desktop, спробуйте встановити час виконання MS Visual C (наприклад, перезапустити програму встановлення та вибрати лише цей компонент).
  • Може бути запущено без використання командного рядка (наприклад, для віддаленого розгортання) з наступними аргументами:

    • /S для тихого;

    • / AllUser (при запуску від імені адміністратора) або /CurrentUser

    • /C = [gFC], щоб вказати компоненти, де:

      g = Скасувати вибір основного компонента ghini.desktop (корисний для додавання додаткового компонента після первинної установки)

      F = вибрати Apache FOP

      C = вибрати MS Visual C runtime

Debian

Between 2009 and 2010 someone packaged the then already obsolete Bauble 0.9.7 for Debian, and the package was included in Ubuntu. That version is still being distributed, regardless being it impossible to install.

Only recently has Mario Frasca produced a new bauble debian package, for the latest bauble.classic version 1.0.56, and proposed for inclusion in Debian. View it on mentors. This version depends on fibra, a package that was never added to Debian and which Mario also has packaged and proposed for inclusion in Debian. Mario has been trying to activate some Debian Developer, to take action. There’s not much more we can do, other than wait for a sponsor, and hoping the package will eventually get all the way to Ubuntu.

Once we get in contact with a Debian Sponsor who will review what we publish on mentors, then we will be definitely expected to keep updating the debian package for ghini.desktop and fibra.

I am not going to explain in a few words the content of several books on Debian packaging. Please choose your sources. For a very compact idea of what you’re expected to do, have a look at scripts/pubish.sh.