Авторские статьи

Моя борьба с Oracle SQL Developer Data Modeler.


В любой игре, если только она не вечная MMORPG, вы рано или поздно встретите финального босса и закончите игру с победой. Увлекательный квест с инструментом упаковки snapcraft вам не гарантирует, что уровень ваших познаний позволит запихать программу в самодостаточный пакет snap. Но чувство когда удалось победить все проблемы и оформить для людей программу, которая никогда не была легко доступна пользователям, не просто передать и описа́ть.

Начало

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

Более подробно как паковать программы в snap будет разжёвано в поздних статьях на примере GTK программы DeaDBeeF. Упаковка там сложнее в том плане, что программа собирается из исходников, юзает графический тулкит GTK, который цепляет +100500 компонентов. Искренне хотел, чтобы автор проекта сам выставлял проект в Ubuntu Store. Поделился с ним наработками и дал время, но, не зная окончательного решения upstream, не удержался и выложил программу сам под именем deadbeef-vs.

База

Сегодня опять Java программа и базовые приёмы при упаковке софта в snap. Нам нужен пустой каталог и в нём создаётся пустой файл snapcraft.yaml. Пишем в нём базовые поля: name, version, summary, description, confinement, architectures.

На примере Oracle SQL Developer Data Modeler.

name: osddm
version: "4.1.3.901-snap1"
summary: Oracle SQL Developer Data Modeler
description: |
    Oracle SQL Developer Data Modeler is a free graphical tool that enhances productivity and simplifies data modeling tasks. 
    Using Oracle SQL Developer Data Modeler users can create, browse and edit, logical, relational, physical, multi-dimensional, 
    and data type models. The Data Modeler provides forward and reverse engineering capabilities and supports collaborative 
    development through integrated source code control. The Data Modeler can be used in both traditional and in Cloud environments.
confinement: strict
architectures: [amd64]

Поля имеют самоговорящие названия, но позволю их ещё разжевать:

  • name. Имя пакета, которое станет начальной частью имени итогового файла snap. Если внутри снап пакета в bash скриптах вам нужно манипулировать чем-то, исходя из его имени, то для универсальности и избежания ошибок лучше использовать переменную $SNAP_NAME.
  • version. Версия пакуемой программы. Используйте переменную $SNAP_VERSION внутри снап пакета, если нужно. Версия будет отображена в имени итогового файла. Рекомендую к версии программы добавлять постфикс snapЦИФРА, чтобы в случае своих допущенных проблем выпускать исправления в рамках версии из upstream.
  • summary. Краткое описание пакета, которое будет отображено в выводе консольной команды snap list|find
  • description. Длинное описание, которое традиционно пишется в несколько строк и символ | начинает нулевую строку.
  • confinement. Режим ограничения. Бывает строгим - strict и для отладки - devmode. В режиме devmode программу не ограничивают её же профилем AppArmor и не фильтруют системные вызовы через seccomp. Рекомендую всегда указывать strict, а для отладки устанавливать тестовый пакет через sudo snap install --devmode app-version.snap. Если вы не справитесь до конца и программа в строгом режиме strict не работает, то в режиме devmode snap пакет можно залить в Ubuntu Store только для каналов beta и edge. То есть простой пользователь не увидит ваше детище через stable канал и не сможет легко установить программу через GNOME Software. В консоли пользователю придётся писать sudo snap install your-snap-package --channel=beta. Старайтесь до победного - программа работает в strict ограничениях!
  • architectures. Архитектура программы внутри пакета, доступна через переменную $SNAP_ARCH. Можно создать мультиархитектурный пакет, но это моё слабое место и детально ещё с данным вопросом не разбирался. Пока решил сосредоточится только на 64 битной архитектуре. Если ука́жите архитектуру программы типа architectures: [i386, amd64], то должны будете предоставить внутри пакета программу и её библиотеки в данных архитектурах и сможете в стартовых скриптах использовать конструкции типа:
    if [ "$SNAP_ARCH" == "amd64" ]; then
      ARCH="x86_64-linux-gnu"
    elif [ "$SNAP_ARCH" == "armhf" ]; then
      ARCH="arm-linux-gnueabihf"
    else
      ARCH="$SNAP_ARCH-linux-gnu"
    fi

В моём случае (одна архитектура в лице 64 бит) итоговое имя файла будет osddm_4.1.3.901-snap1_amd64.snap.

Apps

Следующим шагом в snapcraft.yaml добавляем раздел apps и в него свои "программы".

apps:
 osddm:
  command: usr/bin/run.sh
  plugs: [network, network-bind, x11, home, unity7, gsettings]

Заметьте что имя "бинарника" osddm совпадает с именем пакета, что позволит пользователю вызывать программу по имени osddm, что неявно вызовет osddm.osddm. Некоторых коробит такой вид программы в стиле $имя_снап.$имя_программы, но вы должны понять, что внутри snap пакета могут идти несколько "программ", должен быть способ вызвать их и нужно решить вопрос с возможным совпадением одинаковых имён программ из разных пакетов. Ведь вы можете представить в системе программу music-player и другой снапкрафтер в своём пакете ненамеренно представить плеер с таким же именем.

Чтобы окончательно прояснить вопрос со множеством "бинарников" в снап пакете, представлю вам эталонный hello-world пакет.
sudo snap install hello-world ; cd /snap/hello-world/current/ ; tree.

.
├── bin                 ← this directory structure is just for convenience
│   ├── echo              there is no hardcoded structure requirement other
│   ├── env               than meta/snap.yaml
│   ├── evil
│   ├── sh
│   ├── showdev
│   └── usehw
└── meta                ← your snap must have this directory
    ├── icon.png        ← no prizes for guessing what this is
    └── snap.yaml       ← this is the required metadata

В его snapcraft.yaml (в пакете он лежит как meta/snap.yaml) раздел apps выглядит так

apps:
  env:
    command: bin/env
  evil:
    command: bin/evil
  sh:
    command: bin/sh
  hello-world:
    command: bin/echo

Свой враппер

Но возвращаемся к Oracle SQL Developer Data Modeler и к строкам

  command: usr/bin/run.sh
  plugs: [network, network-bind, x11, home, unity7, gsettings]

Почему run.sh намекает на bash скрипт и там не указан бинарник программы? Дело в том, что snapcraft автоматически предоставляет очень куцый, по крайней мере пока, скрипт-враппер command-osddm.wrapper, который будет лежать в корне snap пакета и в нём строки:

#!/bin/sh
export PATH="$SNAP/bin:$SNAP/usr/bin:$PATH"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$SNAP/lib:$SNAP/usr/lib:$SNAP/lib/x86_64-linux-gnu:$SNAP/usr/lib/x86_64-linux-gnu"
export LD_LIBRARY_PATH="$SNAP/usr/lib/x86_64-linux-gnu/mesa-egl:$SNAP/usr/lib/x86_64-linux-gnu/mesa:$LD_LIBRARY_PATH"
export LD_LIBRARY_PATH="$SNAP/usr/lib/x86_64-linux-gnu:$SNAP/usr/lib/x86_64-linux-gnu/pulseaudio:$LD_LIBRARY_PATH"
LD_LIBRARY_PATH=$SNAP_LIBRARY_PATH:$LD_LIBRARY_PATH
exec "$SNAP/usr/bin/run.sh" "$@"

Как вы видите там реально базовые вещи в лице переменных PATH и LD_LIBRARY_PATH. Этого, к сожалению, не достаточно. По опыту скажу, что между стандартным враппером и запуском программы очень нужен ещё один ваш враппер-скрипт, которые подрихтует напильником нужное. Обратите внимание, что путь к программе (стартовому скрипту) в snapcraft.yaml указан в "относительном" стиле без / впереди - usr/bin/run.sh. usr/bin/ намекает, что это не системный /usr/, а usr/ внутри snap пакета. Обратите внимание, что в стандартном враппере наш путь был преобразован в exec $SNAP/usr/bin/run.sh. Переменная $SNAP хранит значение пути, куда будет установлен snap пакет. Обычно это /snap/$SNAP_NAME/$SNAP_REVISION/, то есть $SNAP = /snap/$SNAP_NAME/$SNAP_REVISION/. Содержимое run.sh будет ниже.

Plugs

Что такое plugs и с чем его едят? Snap пакет самодостаточен и в нём нет понятия зависимости из мира deb как класс. Но будучи изолированным, софту нужно получать доступ к вещам за пределами тюрьмы-снап-пакета. По умолчанию, система (снап пакет ubuntu-core) предоставляет следующие слоты: camera, cups-control, firewall-control, gsettings, hardware-observe, home, locale-control, log-observe, modem-manager, mount-observe, network, network-bind, network-control, network-manager, network-observe, opengl, optical-drive, ppp, pulseaudio, snapd-control, system-observe, timeserver-control, timezone-control, unity7, x11. К нужным для вас слотам можно сделать connect и получить требуемое.

Заранее из snapcraft.yaml connect'ы просятся именно так - plugs: [network, network-bind, x11, home, unity7, gsettings]
В данном примере просим дать сетевой доступ network, возможность bind на сетевой интерфейс аля сервис - network-bind, возможность графической программе через свои тулкиты отобразить в X11, доступ к домашней папке home, доступ к технологиям Unity типа глобального меню и т.д., доступ к gsettings даст так же возможность общения по шине DBus.

Пользователь в дальнейшем может добавить коннекты или разорвать существующие. Пока это возможно только в консоли через snap connect/disconnect, но разработчиками планируется создание графической утилиты. Естественно, что разрыв соединения точно приведёт в потери части функционала программы и даже к её неработоспособности в ряде случаев. Например, в почтовой рассылке разработчиков читал что текущая реализация дисконнекта слота network очень груба и многие сетевые программы справедливо ругаются и падают, когда им отсекают их сетевые возможности. Разрабы хотят сделать реализацию отъёма слота network в стиле - "нет провода". То есть, отняв у сетевой программы коннект к слоту network, мы как бы говорим программе, что внутри её тюрьмы есть сетевая карта, но из неё "вынули провод".

Кусочки

Кусочек dm-files

Parts - это ваши кусочки с произвольными именами, которые делают полезные для вас вещи. Snapcraft расширяется через систему плагинов и команда snapcraft list-plugins выводит на данный момент:

ant        catkin  copy  jdk     kernel  maven  nodejs   python3  tar-content
autotools  cmake   go    kbuild  make    nil    python2  scons  

Добавляю раздел parts и первый кусочек dm-files, который использует плагин copy для размещения нужных файлов и каталогов в нужных местах.

parts:
  dm-files:
   plugin: copy
   files:
    run.sh: usr/bin/run.sh
    ddm/* : /
    ddm/opt/datamodeler/datamodeler.desktop : usr/share/applications/datamodeler.desktop
    ddm/opt/datamodeler/osddm.png : usr/share/icons/hicolor/128x128/apps/osddm.png
   after: [integration]

Разберём подробнее:

  • run.sh: usr/bin/run.sh
    Мой враппер, чей код рассмотрим ниже, лежит в папке рядом со snapcraft.yaml и прошу разместить его usr/bin/run.sh, так как usr/bin/ находится в переменной PATH.
  • ddm/* : /
    Скачанный с официального сайта Oracle SQL Developer Data Modeler в виде rpm был распакован в ddm/ и представлен в виде дерева каталогов.

    .
    ├── opt/
    │   └── datamodeler/
    │       ├── configuration/
    │       ├── datamodeler/
    │       ├── datamodeler.desktop
    │       ├── datamodeler.exe
    │       ├── datamodeler.sh*
    │       ├── dropins/
    │       ├── dvt/
    │       ├── equinox/
    │       ├── external/
    │       ├── icon.png
    │       ├── ide/
    │       ├── jdbc/
    │       ├── jdev/
    │       ├── jlib/
    │       ├── modules/
    │       ├── netbeans/
    │       ├── osddm.png
    │       ├── rdbms/
    │       ├── sleepycat/
    │       ├── sqldeveloper/
    │       ├── svnkit/
    │       └── userfiles/
    └── usr/
        └── local/
            └── bin/
    

    Прошу всё содержимое ddm/* разместить в корне /, но это корень снап пакета программы, а на корень / системы. Это важная грань и её следует понимать. Меня устраивает будущий путь к рабочему каталогу программы opt/datamodeler/ и всё остальное будет отталкиваться от этого.

  • ddm/opt/datamodeler/datamodeler.desktop : usr/share/applications/datamodeler.desktop
    Внутри datamodeler.desktop стало после правки двух параметров - Icon и Exec.

    [Desktop Entry]
    Encoding=UTF-8
    Name=Oracle Data Modeler
    Comment=Oracle Data Modeler
    Icon=osddm.png
    Exec=run.sh
    Terminal=false
    Type=Application
    

    Убрал абсолютные пути. Абсолютные пути, начинающиеся с /, обычно ошибка, так как это означает, что кто-то или что-то будет искать указанное с корня системы и получит отлуп от системы мандатного доступа AppArmor. Параметр Icon содержит только упоминание имени файла без пути, так как ниже мы попросим скопировать иконку в нужное место. Параметр Exec указывает на мой враппер, лежащий в usr/bin/ и находящийся в переменной PATH.

  • ddm/opt/datamodeler/osddm.png : usr/share/icons/hicolor/128x128/apps/osddm.png
    Прошу иконку разместить в правильном с точки зрения Filesystem Hierarchy Standard (FHS) месте.
  • after: [integration]
    Прошу snapcraft кусочек dm-files обрабатывать после кусочка integration. Это не обязательно, но удобно, когда хотелось бы задать порядок обработки parts.

Кусочек integration

Кусочек по имени integration использует ничего не делающий плагин nil, чтобы с помощью stage-packages можно было указать какие пакеты из стандартных репозиториев Ubuntu snapcraft должен скачать и добавить их содержимое в будущий snap пакет. Вы ещё не забыли что снап пакет должен быть самодостаточным? "Всё своё ношу с собой".

  integration:
   plugin: nil
   stage-packages:
    - gnome-icon-theme
    - file
    - sed
    - bash
    - openjdk-8-jre
    - locales
    - fonts-freefont-ttf
    - libxkbcommon0 
    - ttf-ubuntu-font-family
    - dmz-cursor-theme
    - light-themes
    - shared-mime-info
    - libgtk2.0-0
    - libgdk-pixbuf2.0-0
    - libglib2.0-bin
    - unity-gtk2-module
    - libcanberra-gtk-module
    - libc-bin
    - libx11-6
    - libxtst6
    - zlib1g
    - libc6

Баги, портящие кровь

Здесь нужно сделать перерыв и объяснить один момент. Инструмент упаковки snapcraft находится под активной разработкой, как и вся новая технология пакетов snap. Вся эта братия находится на переднем фронте разработки и не может не содержать багов и шероховатостей. В моём случае из ТРЁХ плагинов (ant, maven, jdk), занимающиеся Java программами, в идеале нужно было взять jdk, который помогает в упаковке Java программ в готовых jar файлах. Ant и maven помогают в сборке Java программ из исходников.

Если сделать дополнительный кусочек java-files вот так

  java-files:
   plugin: jdk
   source: .

то Snapcraft "увидит" Java природу упаковываемой программы и :

  • модифицирует свой стандартный враппер, добавив нужное для Джава.
  • сам добавит актуальный пакет openjdk.

К этому моменту разработчики облегчили жизнь снапкрафтерам и представили облачные кусочки (cloud parts), которые легко использовать, добавив к любому своему кусочку строку
after: [desktop/xxx]
где xxx - gtk2, gtk3, qt4, qt5, glib-only.

Облачные кусочки (cloud parts) - это эталонный набор пакетов в раздел stage-packages и эталонный враппер desktop-launch.

Но на определённом этапе, snapcraft начал выводит сообщение, что разные мои кусочки и задействованные облачные кусочки начали добавлять одно и тоже, создав конфликт. Строка сообщения гласила что-то типа
Parts 'desktop/gtk3' and 'java-files' have the following file paths in common which have different contents:
usr/share/pkgconfig/shared-mime-info.pc

Нашёл открытый отчёт о баге Same packages pulled twice with different timestamps cause clash и подтвердил, добавив комментарий. Баг на дату написания статьи остаётся не закрытым и в состоянии High. Ну что можно сказать, кроме слова б%№ть? Сидеть ждать от моря погоды?
Решил:

  • просто выбросить помощь от разработчиков в лице cloud parts и не использовать after: [desktop/xxx]
  • не юзать плагин jdk, а добавлять Java машину через пакет openjdk-8-jre в своих кусочках в секции stage-packages


Это легко сказать и трудно сделать. Выбросив помощь разработчиков в лице их cloud parts, лишился ещё и их эталонного враппера desktop-launch, которые делает такие вещи, до которых мне своим умом просто не дойти. Спёр эталонный desktop-launch и под видом run.sh с моими дополнениями он будет рассмотрен ниже. Так же спёр эталонный набор пакетов, просто добавив их в свой кусочек integration. Давайте вернёмся к нашим баранам.

Работаем напильником

Осталось вызвать snapcraft команду в папке с файлом snapcraft.yaml и всё? Щазззз. В идеальном мире вы могли бы указать источник программы в yaml, snapcraft скачал его и упаковал в готовый snap пакет вместе с нужными файлами. В идеальном мире снапкрафтер мог бы поделится созданным snapcraft.yaml с апстримом проекта и они уже сами легко паковали программу. Но реальный мир суров - нужно подправить различные нюансы в программе и её ручонки аккуратно завернуть внутрь смирительной рубашки.

Программа вместе со своей свитой внутри снап пакета будет сжата squashfs и доступна ТОЛЬКО-ДЛЯ-ЧТЕНИЯ по пути в переменной $SNAP. Для ЗАПИСИ чего-либо у вас будет путь $SNAP_USER_DATA.

Всё, игра началась! Так как упаковка даже готовой программы в jar файлах долгий процесс и исследование неизвестной программы без исходников чревато множеством итераций упаковки, то делаем ход конём. Копируем программу со сборочного сервера в свою основную систему в системный путь /opt/datamodeler/ и делаем 99% имитацию будущего положения: каталог для чтения, где обитает программа, и каталог для записи в лице ~/. Каталог /opt/datamodeler/ имитирует $SNAP, а ~/ имитирует $SNAP_USER_DATA.

Делаем для чистоты эксперимента владельцем каталога пользователя root и добавляем, чтобы файлы на чтение точно были доступны всем (a+r).

sudo chown -R root:root /opt/datamodeler/
sudo chmod -R a+r /opt/datamodeler/

Теперь осталось за малым crazy lol. Нужно, чтобы запущенный из под обычного пользователя, Oracle SQL Developer Data Modeler корректно работал. Он может создавать в моей домашней папке ~/ что ему угодно, но он не должен и не сможет создавать или писа́ть в каталог /opt/datamodeler/.

Начнём исследование!

Стартовый для Linux систем скрипт opt/datamodeler/datamodeler.sh содержит cd "`dirname $0`"/datamodeler/bin && bash datamodeler
М-м-м, определяется где находится программа в данный момент и осуществляется переход в datamodeler/bin и запуск "bash datamodeler". Так и запишем в stage-packages, что требуется одноименный пакет bash, который хранит оболочку bash.

Анализируем вызываемый bash скрипт opt/datamodeler/datamodeler/bin/datamodeler. Ищём намёки на абсолютные пути. Вроде нет их. Шапка скрипта

#-----------------------------------------------------------------------------
#  toAbsPath() takes two arguments
#    1) a pathname (assumed to point to a file)
#    2) a directory that the pathname is relative to
#
#  and converts the pathname to an absolute path (if necessary), resolving
#  any "." or ".." in the absolute path.  The result is echoed to STDOUT.
#-----------------------------------------------------------------------------

и всякие dirname и basename укрепляют нас в вере, что разработчики продумали тот момент, что их детище будет запущено из различных мест в файловой системе. Нам это на руку. Строка

"`dirname "${SCRIPT}"`/../../ide/bin/launcher.sh"

и вот мы двигаемся к другому скрипту launcher.sh, лежащему в opt/datamodeler/ide/bin/.

Launcher.sh не просто скрипт, а скриптище! Особого желания его править нет, но придётся. Множество вызовов программ с абсолютными путями. Сейчас это работает в моей хостовой системе, а внутри снап пакета - НЕТ! Пока ничего не трогаем, так как цель - не погрязнуть в переписывании скрипта. Находим традиционный розыск установленной Java машины.

  
  # Search for Java in the following order:
  #  0) $OIDE_JAVA_HOME. This serves as a global override.
  #  1) ../../jdk/bin/java. Some products have a shipped JDK in this directory.
  #  2) ../../../jdk/bin/java. Some products have a shipped JDK in this
  #     directory, and it points to the JDK for JDEVADF internal developers.
  #  3) $JAVA_HOME/bin/java. If JAVA_HOME is set, we should use that
  #     to determine the JDK to use.
  #  4) A java in /usr/java/jdk8*
  #  5) A java in /usr/java8* (AIX)
  #  6) Any java on the PATH.

Мы можем через OIDE_JAVA_HOME или JAVA_HOME указать путь к Джава машине. В своём враппере run.sh делаю первые наброски: указываю путь к Java через JAVA_HOME и этот путь добавляю в PATH. Полный run.sh будет ниже.

export JAVA_HOME="$SNAP/usr/lib/jvm/java-8-openjdk-amd64/"
export PATH="$JAVA_HOME:$SNAP/usr/lib/x86_64-linux-gnu/:$SNAP/opt/datamodeler/datamodeler/bin:$SNAP/usr/lib/jvm/java-8-openjdk-amd64/bin:$SNAP/opt/datamodeler/ide/bin:$PATH"
...
exec $SNAP/opt/datamodeler/datamodeler.sh

Пробуем создать snap пакет на сборочном сервере с помощью snapcraft. В тестовой виртуальной машине с Ubuntu 16.04 LTS ставим первый билд - sudo snap install --devmode osddm_4.1.3.901-snap1_amd64.snap. И первый блин комом! Запуск osddm требует указать путь к JDK, хотя моя хостовая машина ничего не выводила. По тексту сообщения вышел на кусок кода в launcher.sh, где прямо говорилось, что если предоставляемая Java машина обладает нужным, то просто добавьте SetSkipJ2SDKCheck true. Но куда это добавлять? Нашёл строку

setskipj2sdkcheck)   NEWARG="SetSkipJ2SDKCheck" ;;

и попробовал в opt/datamodeler/datamodeler.sh добавить cd "`dirname $0`"/datamodeler/bin && bash datamodeler --setskipj2sdkcheck Но номер у меня не удался. Помог другой способ. Если строка SetSkipJ2SDKCheck true есть в файле .data_modeler/1.0.0.0.0/product.conf, то osddm перестаёт ругаться. В run.sh нужно добавить строки ДО вызова программы

mkdir -p "$SNAP_USER_DATA/.data_modeler/1.0.0.0.0"
echo "SetSkipJ2SDKCheck true" > "$SNAP_USER_DATA/.data_modeler/1.0.0.0.0/product.conf"

На этом этапе osddm стартовал, быстро мелькал сплэш экран и всё - программа завершалась. Добавил --verbose в opt/datamodeler/datamodeler.sh - cd "`dirname $0`"/datamodeler/bin && bash datamodeler --verbose. В launcher.sh заработали строки EchoIfVerbose, которые стали выводить не лишнюю для меня информацию, но понимание ситуации не улучшили. В данном месте стало грустно. У меня на руках Java программа, а я не разбираюсь ни в Джава, ни в данной программе. Отлаживать программы никогда не умел. Взгляд упал на файл opt/datamodeler/datamodeler/bin/logging.conf, чьё название намекает на конфигурирование уровня журналирования. Нужно поднять уровень журналирования! На просторах Интернет нашёл советы от профи - как повысить уровень информирования в консоль о ходе работы джава программы.
Внёс строки

.level=SEVERE
java.util.logging.ConsoleHandler.level=ALL
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
oracle.dbtools.logging.LogPaneHandler.level=ALL

И? Строк стало так много, что старт программы замедлился в разы ! Но теперь хотя бы можно найти проблему. Оказалось, что такой сложный комплекс как Oracle SQL Developer Data Modeler состоит из различных компонент и один из них обнаружил, что его каталог opt/datamodeler/netbeans/platform/ находится на разделе со свободным местом в 0 байт. То есть он ругается не на то, что каталог не доступен для записи, а именно что каталог находится там где свободного места = 0 байт.

"Нам нужна собака для полётов в космос!" - сказал К.Э. Циолковский.
"Вот сука!" - сказал И.П. Павлов.

И как быть? Мысль только одна. Нужно вынести каталог platform/ в $SNAP_USER_DATA/ и заюзать его оттуда. В run.sh пишу прототип, если нет platform при первом запуске программы, то копирую нужное.

if [ ! -e "$SNAP_USER_DATA/platform" ]; then
     mkdir -p "$SNAP_USER_DATA/platform"
     cp --preserve=timestamps -dR "$SNAP/opt/datamodeler/netbeans/platform" "$SNAP_USER_DATA"
fi

А кто юзает каталог platform? Оказалось в opt/datamodeler/ide/bin/ide.conf нужно подправить часть строк

AddJavaLibFile  ${SNAP_USER_DATA}/platform/lib/boot.jar
AddJavaLibFile  ${SNAP_USER_DATA}/platform/lib/org-openide-util-ui.jar
AddJavaLibFile  ${SNAP_USER_DATA}/platform/lib/org-openide-util.jar
AddJavaLibFile  ${SNAP_USER_DATA}/platform/lib/org-openide-util-lookup.jar
AddJavaLibFile  ${SNAP_USER_DATA}/platform/lib/org-openide-modules.jar
AddVMOption  -Dnetbeans.home=${SNAP_USER_DATA}/platform/

И? На тебе под дых, чтобы не расслаблялся. Oracle SQL Developer Data Modeler стал ругаться, что его домашняя папка, которая расположена в $SNAP_USER_DATA совпадает с путём к platform. Нуёптвоюмать! Нужна срочно ещё папка для записи. Недавно введена папка, которая не поддерживает версионность, и доступна через переменную $SNAP_USER_COMMON = /home/$user/snap/$app-name/common/. Но вызов в скрипте run.sh
mkdir -p "$SNAP_USER_COMMON"
вызывал отказ в доступе. Кинулся к разрабам в почтовой рассылке - ответ просто убил. Это типа бага, пока вызывайте snap run ossdm; ossdm. Хорошо что я плохо выражаю свои мысли на английском и тем более отборные маты. Ну как так-то? Вместо красивого вызова программы osddm, просить пользователя однократно вызывать snap run ossdm; ossdm? И где мне это просить? Быть в шаге от победы и отложить на неопределённый срок упаковку программы, которая готова на 99,99%. Р-р-р.

Так просто не сдамся, вдумчиво старался понять последний вызов мне. Что точно не нравится Oracle SQL Developer Data Modeler? Осенило, что ему не нравится тот факт, что папка $SNAP_USER_DATA/platform/ НА ОДНОМ УРОВНЕ иерархии с папкой $SNAP_USER_DATA/.oraclesqldeveloperdatamodeler/. Окей, бэби! Сдвигаю папку platform вглубь - ${SNAP_USER_DATA}/deep/platform/. Бинго! Oracle SQL Developer Data Modeler милостиво дал добро и запустился во всей красе. Прошёл эту игру, замочил босса на уровне.

В процессе тестирования работы программы в ограниченной профилями AppArmor среде вырисовалась маленькая шероховатость. Oracle SQL Developer Data Modeler при сохранении вашей работы, пытается осуществлять частичную запись в каталог, откуда он стартовал и естественно в этом ему отказано. Оказалось есть переменные в конфигурационном файле, которые помогут переопределить нужные папки. Это переменная def_sys_types_path. Создал дефолтный прообраз будущего конфигурационного файла ddm/opt/datamodeler/userfiles/product-preferences.xml и значения заполнил метками, которые заменит sed при первом старте программы.


В run.sh есть строки

mkdir -p "$SNAP_USER_DATA/.oraclesqldeveloperdatamodeler/system4.1.3.901/o.datamodeler"
UUID=$(cat /proc/sys/kernel/random/uuid)
# меняем XYZZYX на ${SNAP_USER_DATA}/tmp
sed "s#XYZZYX#${SNAP_USER_DATA}/tmp#g" "$SNAP/opt/datamodeler/userfiles/product-preferences.xml" | tee -a "$SNAP_USER_DATA/.oraclesqldeveloperdatamodeler/system4.1.3.901/o.datamodeler/product-preferences2.xml"
# меняем ZXCCXZ на заранее полученный UUID
sed "s#ZXCCXZ#${UUID}#g" "$SNAP_USER_DATA/.oraclesqldeveloperdatamodeler/system4.1.3.901/o.datamodeler/product-preferences2.xml" | tee -a "$SNAP_USER_DATA/.oraclesqldeveloperdatamodeler/system4.1.3.901/o.datamodeler/product-preferences.xml"
# копируем нужный файл types.xml в каталог def_sys_types_path (${SNAP_USER_DATA}/tmp)
cp --preserve=timestamps "$SNAP/opt/datamodeler/datamodeler/types/types.xml" "$SNAP_USER_DATA/tmp/types.xml"

Манипуляции с параметром instanceGuid нужны, чтобы у разных пользователей был различный UUID, что важно в определённых местах. Хотелось сделать всем красиво. Разные UUID - это правильно.

Итог

Всё ли сделано? Из задуманного - всё. Программа корректно стартует и работает, сохраняя результаты пользователя. В данный момент можно получить через процедуру Update много вкусняшек к программе (~1,5 Гб), но корректно установить нельзя, так как каталог программы доступен только на чтение. Поэтому временно отключил проверку обновлений на старте. Такой серьёзный вызов требует серьёзного подхода и оставлен на вторую битву с Oracle SQL Developer Data Modeler. Нужно разместить скачанное в $SNAP_USER_DATA и подключить к программе. Постараюсь реализовать, но не обещаю, что справлюсь с таким вызовом.

На этом всё! Желаю всем поиграть в эту игру - "Snapcraft. Упакуй Рой"
Первый snap пакет. Java программа LanguageTool. sudo snap install languagetool
Второй snap пакет. GTK программа DeaDBeeF. sudo snap install deadbeef-vs
Третий snap пакет. Java программа TuxGuitar. sudo snap install tuxguitar-vs
Четвёртый snap пакет. Java программа Vuze. sudo snap install vuze-vs
Пятый snap пакет. Java программа osddm. sudo snap install osddm
Шестой snap пакет. PAC (Perl Auto Connector). sudo snap install pac-vs

Все пакеты в Ubuntu Store.
snap find vs

Name          Version          Developer  Notes  Summary
deadbeef-vs   0.7.2-snap1      vs         -      The Ultimate Music Player
languagetool  3.4-snap2        vs         -      LanguageTool
osddm         4.1.3.901-snap1  vs         -      Oracle SQL Developer Data Modeler
tuxguitar-vs  1.3.2-snap2      vs         -      TuxGuitar
vuze-vs       5.7.2.0-snap1    vs         -      Vuze is a powerful, open source, bittorrent client.

Полностью snapcraft.yaml.

name: osddm
version: "4.1.3.901-snap1"
summary: Oracle SQL Developer Data Modeler
description: |
    Oracle SQL Developer Data Modeler is a free graphical tool that enhances productivity and simplifies data modeling tasks. 
    Using Oracle SQL Developer Data Modeler users can create, browse and edit, logical, relational, physical, multi-dimensional, 
    and data type models. The Data Modeler provides forward and reverse engineering capabilities and supports collaborative 
    development through integrated source code control. The Data Modeler can be used in both traditional and in Cloud environments.
confinement: strict
architectures: [amd64]

apps:
  osddm:
    command: usr/bin/run.sh
    plugs: [network, network-bind, x11, home, unity7, gsettings]

parts:
  dm-files:
   plugin: copy
   files:
    run.sh: usr/bin/run.sh
    ddm/* : /
    ddm/opt/datamodeler/datamodeler.desktop : usr/share/applications/datamodeler.desktop
    ddm/opt/datamodeler/osddm.png : usr/share/icons/hicolor/128x128/apps/osddm.png
   after: [integration]

  integration:
   plugin: nil
   stage-packages:
    - gnome-icon-theme
    - file
    - sed
    - bash
    - openjdk-8-jre
    - locales
    - fonts-freefont-ttf
    - libxkbcommon0 
    - ttf-ubuntu-font-family
    - dmz-cursor-theme
    - light-themes
    - shared-mime-info
    - libgtk2.0-0
    - libgdk-pixbuf2.0-0
    - libglib2.0-bin
    - unity-gtk2-module
    - libcanberra-gtk-module
    - libc-bin
    - libx11-6
    - libxtst6
    - zlib1g
    - libc6

Полностью run.sh, основанный на эталонном desktop-launch от разработчиков. Мой вклад начинается со строки vasilisc part, так как англоязычные разработчики не утруждают себя вопросами локализации.

#!/bin/bash

echo "Please wait, this may take a minute. "

###############################################
# Launcher common exports for any desktop app #
###############################################
export JAVA_HOME="$SNAP/usr/lib/jvm/java-8-openjdk-amd64/"
export PATH="$JAVA_HOME:$SNAP/usr/lib/x86_64-linux-gnu/:$SNAP/opt/datamodeler/datamodeler/bin:$SNAP/usr/lib/jvm/java-8-openjdk-amd64/bin:$SNAP/opt/datamodeler/ide/bin:$PATH"

export UBUNTU_MENUPROXY=

needs_update=true

. ~/.last_revision 2>/dev/null || true
if [ "$SNAP_DESKTOP_LAST_REVISION" = "$SNAP_REVISION" ]; then
  needs_update=false
fi
[ $needs_update = true ] && echo "SNAP_DESKTOP_LAST_REVISION=$SNAP_REVISION" > ~/.last_revision

if [ "$SNAP_ARCH" == "amd64" ]; then
  ARCH="x86_64-linux-gnu"
elif [ "$SNAP_ARCH" == "armhf" ]; then
  ARCH="arm-linux-gnueabihf"
else
  ARCH="$SNAP_ARCH-linux-gnu"
fi

# XKB config
export XKB_CONFIG_ROOT=$SNAP/usr/share/X11/xkb

# Mesa Libs
export LD_LIBRARY_PATH=$SNAP/usr/lib/$ARCH/mesa:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$SNAP/usr/lib/$ARCH/mesa-egl:$LD_LIBRARY_PATH

# Tell libGL where to find the drivers
export LIBGL_DRIVERS_PATH=$SNAP/usr/lib/$ARCH/dri
export LD_LIBRARY_PATH=$SNAP/usr/lib/x86_64-linux-gnu/:$SNAP/usr/lib/$ARCH/dri:$LD_LIBRARY_PATH

# Pulseaudio export
export LD_LIBRARY_PATH=$SNAP/usr/lib/$ARCH/pulseaudio:$LD_LIBRARY_PATH

# XDG Config
export XDG_CONFIG_DIRS=$SNAP/etc/xdg:$SNAP/usr/xdg:$XDG_CONFIG_DIRS

# Define snaps' own data dir
export XDG_DATA_DIRS=$SNAP_USER_DATA:$SNAP/usr/share:$XDG_DATA_DIRS

# Set XDG_DATA_HOME to local path
export XDG_DATA_HOME=$SNAP_USER_DATA/.local/share
export XDG_DATA_DIRS=$XDG_DATA_HOME:$XDG_DATA_DIRS
mkdir -p $XDG_DATA_HOME

# Set cache folder to local path
export XDG_CACHE_HOME=$SNAP_USER_DATA/.cache
mkdir -p $XDG_CACHE_HOME

# Font Config and themes
export FONTCONFIG_PATH=$SNAP/etc/fonts/conf.d
export FONTCONFIG_FILE=$SNAP/etc/fonts/fonts.conf
if [ $needs_update = true ]; then
  rm -rf $XDG_DATA_HOME/{fontconfig,fonts,fonts-*,themes}
  ln -sf $SNAP/usr/share/{fontconfig,fonts,fonts-*,themes} $XDG_DATA_HOME
  ln -sf $SNAP/usr/share/themes $SNAP_USER_DATA/.themes
fi

# Build mime.cache
# needed for gtk and qt icon
if [ $needs_update = true ]; then
  rm -rf $XDG_DATA_HOME/mime
  if [ `which update-mime-database` ]; then
    cp --preserve=timestamps -dR $SNAP/usr/share/mime $XDG_DATA_HOME
    update-mime-database $XDG_DATA_HOME/mime
  fi
fi
##############################
# GTK launcher specific part #
##############################

# select gtk version
#. $SNAP/flavor-select
USE_gtk3=false

# Gdk-pixbuf loaders
export GDK_PIXBUF_MODULE_FILE=$XDG_CACHE_HOME/gdk-pixbuf-loaders.cache
export GDK_PIXBUF_MODULEDIR=$SNAP/usr/lib/$ARCH/gdk-pixbuf-2.0/2.10.0/loaders

if [ $needs_update = true ]; then
  rm -f $GDK_PIXBUF_MODULE_FILE
  $SNAP/usr/lib/$ARCH/gdk-pixbuf-2.0/gdk-pixbuf-query-loaders > $GDK_PIXBUF_MODULE_FILE
fi

# Gio modules and cache
export GIO_MODULE_DIR=$XDG_CACHE_HOME/gio-modules
if [ $needs_update = true ]; then
  rm -rf $GIO_MODULE_DIR
  mkdir -p $GIO_MODULE_DIR
  ln -s $SNAP/usr/lib/$ARCH/gio/modules/*.so $GIO_MODULE_DIR
  $SNAP/usr/lib/$ARCH/glib-2.0/gio-querymodules $GIO_MODULE_DIR
fi

# GI repository
export GI_TYPELIB_PATH=$SNAP/usr/lib/girepository-1.0:$SNAP/usr/lib/$ARCH/girepository-1.0

if [ "$USE_gtk3" = true ]; then
  export GTK_PATH=$SNAP/usr/lib/$ARCH/gtk-3.0
else
  export GTK_PATH=$SNAP/usr/lib/$ARCH/gtk-2.0
fi

# ibus and fcitx integration
# with those defintions fcitx works unconfined out of the box, ibus requires
# user config to be copied though, https://launchpad.net/bugs/1580463
GTK_IM_MODULE_DIR=$XDG_CACHE_HOME/immodules
export GTK_IM_MODULE_FILE=$GTK_IM_MODULE_DIR/immodules.cache
if [ $needs_update = true ]; then
  rm -rf $GTK_IM_MODULE_DIR
  mkdir -p $GTK_IM_MODULE_DIR
  if [ "$USE_gtk3" = true ]; then
    ln -s $SNAP/usr/lib/$ARCH/gtk-3.0/3.0.0/immodules/*.so $GTK_IM_MODULE_DIR
    $SNAP/usr/lib/$ARCH/libgtk-3-0/gtk-query-immodules-3.0 > $GTK_IM_MODULE_FILE
  else
    ln -s $SNAP/usr/lib/$ARCH/gtk-2.0/2.10.0/immodules/*.so $GTK_IM_MODULE_DIR
    $SNAP/usr/lib/$ARCH/libgtk2.0-0/gtk-query-immodules-2.0 > $GTK_IM_MODULE_FILE
  fi
fi

# Keep an array of data dirs, for looping through them
IFS=':' read -r -a data_dirs_array <<< "$XDG_DATA_DIRS"

# Setup compiled gsettings schema
GS_SCHEMA_DIR=$XDG_DATA_HOME/glib-2.0/schemas
if [ $needs_update = true ]; then
  rm -rf $GS_SCHEMA_DIR
  mkdir -p $GS_SCHEMA_DIR
  for d in "${data_dirs_array[@]}"; do
    schema_dir=$d/glib-2.0/schemas
    if [ "$(ls -A $schema_dir/*.xml 2>/dev/null)" ]; then
      ln -s $schema_dir/*.xml $GS_SCHEMA_DIR
    fi
  done
  $SNAP/usr/lib/$ARCH/glib-2.0/glib-compile-schemas $GS_SCHEMA_DIR
fi

# Enable gsettings user changes
# symlink the dconf file if home plug is connected for read
DCONF_DEST_USER_DIR=$SNAP_USER_DATA/.config/dconf
if [ ! -f $DCONF_DEST_USER_DIR/user ]; then
  if [ -f /home/$USER/.config/dconf/user ]; then
    mkdir -p $DCONF_DEST_USER_DIR
    ln -s /home/$USER/.config/dconf/user $DCONF_DEST_USER_DIR
  fi
fi

# Icon themes cache
if [ $needs_update = true ]; then
  rm -rf $XDG_DATA_HOME/icons
  mkdir -p $XDG_DATA_HOME/icons
  for d in "${data_dirs_array[@]}"; do
    for i in $d/icons/*; do
      if [ -d "$i" ]; then
        theme_dir=$XDG_DATA_HOME/icons/$(basename "$i")
        if [ ! -d "$theme_dir" ]; then
          mkdir -p "$theme_dir"
          ln -s $i/* "$theme_dir"
          if [ -f $SNAP/usr/sbin/update-icon-caches ]; then
            $SNAP/usr/sbin/update-icon-caches "$theme_dir"
          elif [ -f $SNAP/usr/sbin/update-icon-cache.gtk2 ]; then
            $SNAP/usr/sbin/update-icon-cache.gtk2 "$theme_dir"
          fi
        fi
      fi
    done
  done
fi
# vasilisc part
######################################
export I18NPATH=$SNAP/usr/share/i18n
export LOCPATH=$SNAP_USER_DATA
export LC_ALL=$LANG
LANG1=$(echo $LANG | cut -f1 -d.)
ENC=UTF-8
LOC="$LANG"
# generate a locale so we get properly working charsets and graphics
if [ ! -e $SNAP_USER_DATA/$LOC ]; then
  $SNAP/usr/bin/localedef --prefix=$SNAP_USER_DATA -f $ENC -i $LANG1 $SNAP_USER_DATA/$LOC
fi
######################################

if [ ! -e "$SNAP_USER_DATA/debug" ]; then
    mkdir -p "$SNAP_USER_DATA/debug"
    mkdir -p "$SNAP_USER_DATA/tmp"
    printenv > "$SNAP_USER_DATA/debug/debug.log"
fi

if [ ! -e "$SNAP_USER_DATA/deep/platform" ]; then
    mkdir -p "$SNAP_USER_DATA/deep/platform"
    cp --preserve=timestamps -dR "$SNAP/opt/datamodeler/netbeans/platform" "$SNAP_USER_DATA/deep/"

    mkdir -p "$SNAP_USER_DATA/.data_modeler/1.0.0.0.0"
    echo "SetSkipJ2SDKCheck true" > "$SNAP_USER_DATA/.data_modeler/1.0.0.0.0/product.conf"

    mkdir -p "$SNAP_USER_DATA/.oraclesqldeveloperdatamodeler/system4.1.3.901/o.datamodeler"
    UUID=$(cat /proc/sys/kernel/random/uuid)
    sed "s#XYZZYX#${SNAP_USER_DATA}/tmp#g" "$SNAP/opt/datamodeler/userfiles/product-preferences.xml" | tee -a "$SNAP_USER_DATA/.oraclesqldeveloperdatamodeler/system4.1.3.901/o.datamodeler/product-preferences2.xml"
    sed "s#ZXCCXZ#${UUID}#g" "$SNAP_USER_DATA/.oraclesqldeveloperdatamodeler/system4.1.3.901/o.datamodeler/product-preferences2.xml" | tee -a "$SNAP_USER_DATA/.oraclesqldeveloperdatamodeler/system4.1.3.901/o.datamodeler/product-preferences.xml"

    cp --preserve=timestamps "$SNAP/opt/datamodeler/datamodeler/types/custom_report_templates.xml" "$SNAP_USER_DATA/tmp/custom_report_templates.xml"
    cp --preserve=timestamps "$SNAP/opt/datamodeler/datamodeler/types/defaultdomains.xml" "$SNAP_USER_DATA/tmp/defaultdomains.xml"
    cp --preserve=timestamps "$SNAP/opt/datamodeler/datamodeler/types/defaultRDBMSSites.xml" "$SNAP_USER_DATA/tmp/defaultRDBMSSites.xml"
    cp --preserve=timestamps "$SNAP/opt/datamodeler/datamodeler/types/dl_settings.xml" "$SNAP_USER_DATA/tmp/dl_settings.xml"
    cp --preserve=timestamps "$SNAP/opt/datamodeler/datamodeler/types/dr_custom_scripts.xml" "$SNAP_USER_DATA/tmp/dr_custom_scripts.xml"
    cp --preserve=timestamps "$SNAP/opt/datamodeler/datamodeler/types/old_defaultdomains.xml" "$SNAP_USER_DATA/tmp/old_defaultdomains.xml"
    cp --preserve=timestamps "$SNAP/opt/datamodeler/datamodeler/types/types.xml" "$SNAP_USER_DATA/tmp/types.xml"
fi

export TEMPDIR="$SNAP_USER_DATA/tmp"
exec $SNAP/opt/datamodeler/datamodeler.sh
Дата последней правки: 2023-12-27 12:49:08

RSS vasilisc.com   


Разделы

Главная
Новости
Ворох бумаг
Видео Linux
Игры в Linux
Безопасность
Статьи об Astra Linux
Статьи о FreeBSD
Статьи об Ubuntu
Статьи о Snappy
Статьи об Ubuntu Phone
Статьи о Kubuntu
Статьи о Xubuntu
Статьи о Lubuntu
Статьи об Open Source
Карта сайта