Боремся с The ‘Pods…’ target has transitive dependencies that include static binaries

Суть проблемы следующаяя

1. Используем CocoaPods (про Carthage знаю, по некоторым причинам не хочу использовать)
2. Проект на Swift
3. Имеет swift’овые зависимости, поэтому use_frameworks!
4. Имеет старые Objective-C’шные зависимости, в которых есть транзитивные зависимости в которых есть статические либы (something.a, можно в vendored_libraries)

При попытке сделать pod install получаем

The ‘Pods-…’ target has transitive dependencies that include static binaries

Сие подробно дискутируется тут

https://github.com/CocoaPods/CocoaPods/issues/2926

и тут

https://github.com/CocoaPods/CocoaPods/issues/3289

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

pre_install do |installer|
    def installer.verify_no_static_framework_transitive_dependencies; end
end

Который просто напросто отключает проверку.

P.S. Правда сий хак не всегда помогает :(

Создание новый веток в SVN при работе с GIT-SVN

Если вам требуется создать ветку в SVN, но при этом вы работаете в GIT, то ситуация сначала может показаться странной, ведь если вы создали ветку от svn/trunk то svn dcommit будет отправлять изменения в svn/trunk а не в вашу ветку. Проблема решается достаточно просто, вот рецепт:


# git svn branch foo
# git checkout -b foo -t svn/foo
# ...
# git commit
# git svn dcommit

Передача веток и коммитов между двумя GIT-репозиториями

Случилась такая задача. Есть два git-репозитория (один из которых ко всему прочему соединен с SVN через git-svn). Между ними необходимо передавать ветки и коммиты. Если бы они имели прямую связь через файловую систему или например через http, особых проблем бы не было. Однако, никакой связи кроме человека с флэшкой между этими репозиториями нет. Поэтому пришлось изобретать некий workflow который позволил бы эффективно эту проблему решить.

Вот картинка того, что требуется сделать:

Решить эту проблему можно тремя способами:

  • Скопировать весь локальный репозиторий одной стороны (например, Repo A) и перенести его на флэшке рядом с репозиторием (Repo B) чтобы между ними можно было установить прямую связь через локальную файловую систему
  • Использовать механизм пакетов git’а (git bundles)
  • Использовать механизм патчей (git am)

Первый способ нам не подошел. Хотя бы потому, что репозиторий весит около 1.5 ГБ в сжатом виде. А заливать его приходилось в том числе через RDP соединение. Хотя если у вас есть такая возможность – это самый правильный и самый лучший вариант. Нам увы не подошел, поэтому идем дальше.

Второй способ мы даже активно использовали. Workflow там примерно следующий. С какого-то определенного коммита мы делаем набор патчей для каждого коммита выбранной ветки. На другом репозитории мы переключаемся (или создаем если такой ветки еще нет) на нужную ветку и делаем Apply Patch Serial. В принципе это все работает, но есть проблемы. Проблема первая – фактически в двух репозиториях мы имеем две разные ветки, хоть они одинаково и называются. И содержат разные коммиты, хоть и они содержат одно и то же. Кроме того, возникают нетривиальные вещи связанные с разрешением коллизий. Вообщем, достаточно громоздко и сложно, хотя и работает.

Третий способ – git bundles. Вот его и рассмотрим.

Начнем с того, что git bundle – это такой специальный файл. В который во-первых упакованы нужные ветки и нужные коммиты (вы их указываете сами). Во-вторых, он может представляться как удаленный git-репозиторий, который можно добавить в remotes и работать с ним как с полноценным удаленным репозиторием. Скажем так – этот подход – лайт версия первого подхода, когда вы тащите за собой весь репозиторий. Только здесь вы тащите один файл с тем, что надо. Места он правда может занять тоже весьма нехило, но в общем гораздо меньше (при правильном подходе), чем весь репозиторий.

Теперь давайте рассмотрим как это дело провернуть. Предположим у вас есть репозиторий A из которого необходимо перетащить ветку в репозиторий B (который пуст).

Имеем несколько файлов в репозитории A:

И ветку master:

Теперь нам нужно создать (пересоздать) бандл. Тут два пути – если он уже был создан когда-то, или же его еще не было.

Случай, когда мы создаем новый бандл


// Создаем новый бандл для ветки мастер (веток может быть несколько)
# git bundle create ../master.bundle master
// Помечаем последний коммит на ветке мастер который мы себе забрали (чтобы в следующий раз не тащить все)
// lastR2bundle - просто некоторое имя
# git tag -f lastR2bundle master

Случай, если бандл уже создавали (и появились новые изменения)


// Создаем бандл, но уже с указанием места, с которого его создавали в предыдущий раз
# git bundle create ../master2.bundle lastR2bundle..master
// Обновляем указатель последнего коммита бандла
# git tag -f lastR2bundle master

Теперь бандл у нас есть, необходимо развернуть (обновить) его на другом репозитории RepoB.

В случае если бандл мы принесли первый раз и репозитория нет.

Тогда можно просто склонировать репозиторий прямо с бандла:


// Клонируем репозиторий с бандла в текущую папку
# git clone -b master C:/Temp/gittest/master.bundle .

Ветка автоматически разворачивается до текущего состояния (флаг -b master указывает нужную ветку)

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

Тут несколько сложнее, необходимо зайти в папку .git в корне репозитория и отредактировать там файл config


# создаем новый remote с именем RepoA
[remote "RepoA"]
# указываем путь до бандла
url = C:/Temp/gittest/master.bundle
# указываем способ получения веток из бандла
fetch = +refs/heads/*:refs/remotes/RepoA/*

После этого делаем


# git pull RepoA master

И получаем выгруженную историю из бандла.

Случай, когда бандл уже приносили

В этом случае достаточно заменить старую версию бандла новым, и сделать git pull. Бандлы, сделанные не с самого «начала времен» а с определенного места занимают не так много места.

Надеюсь всем было все понятно и это поможет вам вести удобную разработку с использованием git’а.

P.S. Механизм бандлов работает в обе стороны, изменения в нашей схеме можно переносить не только из RepoA в RepoB, но и наоборот.

docker в Ubuntu через прокси

Чтобы в свою очередь docker мог в ubuntu работать через proxy редактируем файл /etc/default/docker в самый конец добавляем

1
2
export http_proxy="http://login:password@host:port"
export https_proxy="http://login:password@host:port"

и перезапускаем службу docker

1
# sudo service docker restart

После этого можно проверить hello-world

1
#  sudo docker run hello-world

Работа apt-get в Ubuntu через прокси

Чтобы apt-get в Ubuntu заработал через прокси, необходимо создать или добавить в файл /etc/apt/apt.conf.d/proxy Следующие строчки:

1
2
3
Acquire::http::Proxy "http://login:password@host:port";
Acquire::ftp::Proxy "http://login:password@host:port";
Acquire::::Proxy "true";

И все заработает

Решение проблемы с PowerShell

Возникла проблема PowerShell «не удается загрузить файл так как выполнение скриптов запрещено для данной системы»

Решается выключением нафиг этой защиты

1
Set-ExecutionPolicy Unrestricted

О фреймворках JavaScript’овых

В последнее время наблюдаю ситуацию, когда на JavaScript’е пытаются сделать все, что только можно. Тенденция на самом деле пугающая. Популярность понятна – низкий порог вхождения; отсутствие строгих требований к пониманию того, как работают программные системы и распространенность инструментарий (фактически для начала нужен хром и блокнот). Однако, «программисты» на JavaScript’е большей частью люди, далекие от серьезной разработки (существуют конечно и уважаемые гуру, но их как правило гораздо меньше) пишут свой код бездумно и в больших количествах. И очень часто этот код попадает в рабочие проекты. И после этого, когда дело доходит до того, что «система не работает» с этим приходится разбираться. Для того, чтобы немного систематизировать информацию и, дай бог, уменьшить количество такого кода и предназначена эта статья.

Но для начала немного терминологии, которую будем использовать в этой статье. Разделим все Web-страницы, Web-сайты и Web-приложения на два «лагеря» – backend-ориентированные и frontend-ориентированные.

Backend-ориентированные в вопросах обработки бизнес-информации и бизнес-логики опираются на бэкенды, которые написаны как правило на таких языках как Java, PHP, Ruby, Python (надеюсь никого не обидел). Представление в таких приложения как правило не требует каких-то более серьезных вещей кроме как динамика представления данных, обработка событий пользователя и передача их на бэкенд.

Frontend-ориентированные приложения как правило оставляют бэкенду только вопросы взаимодействия с базой данных или другими приложениями и реже вопросы формирования самих представлений. Основная часть работы в таких приложениях ложится на непосредственно frontend, где необходимо кроме собственно динамики представления обеспечивать такие вещи как формирование представлений (сиречь HTML код), обработку переходов и взаимодействия между несколькими представлениями, получение и кэширование данных. Да что там говорить, вообщем-то весь MVC переезжает во Frontend.

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

Backend-ориентированные:

Плюсы:

  • Бизнес-логика работает как правило на более структурированных и более производительных технологиях, нежели JavaScript, который хоть и кажется универсальным, достаточно медленен.
  • Бизнес-логика скрыта от конечного пользователя и заниматься ее реверсом (reverse engineering) он не имеет возможности
  • Как правило в силу большей «взрослости» и более высокого порога вхождения, бэкенды как правило лучше спроектированы и реализованы
  • Благодаря тому, что код бэкенда работает в известном окружении и управляется квалифицированными людьми, допустимые использования как правило шире, чем на JavaScript’е в браузере (который работает в песочнице)
  • Как правило стеки технологий для реализация бэкендов закончены и самостоятельны, как правило вам приходится работать с одной определенной версией стека, следовательно вы можете давать некие гарантии надежности

Минусы:

  • Как правило более сложная разработка, связанная с временем компиляции и более витиеватым развертыванием (привет долгие редеплои на сервере приложений)
  • Более высокий порог вхождения означает более высокую стоимость разработки
  • Необходимость фактического перехода между «экранами», которая выглядит как загрузка страницы в браузере, при медленном соединении может быть проблемой

Frontend-ориентированные

Плюсы:

  • Низкий порог вхождения – большое количество специалистов, которых вы можете нанять (правда о их квалификации лучше задумываться заранее – скупой платит дважды)
  • Ввиде того, что JavaScript – интерпретатор, возможна практически интерактивная разработка
  • Инструменты в виде браузера хром весьма и весьма хороши
  • Отсутствие необходимости перезагружать страницу в браузере

Минусы:

  • Скорость работы. Когда вы запускаете сложное MVC приложение со всей логикой запущенной в JavaScript, производительность решения оказывается как правило ниже плинтуса
  • Спагетти код. Будьте готовы, низкий порог вхождения и отсутствие привычки думать перед написанием кода приводят к печальным результатам
  • Чтобы исправить ситуацию, вам надо будет все переписать
  • Количество браузеров практически неисчислимо, кроме собственно разных вендоров и их моделей (хром, файрфокс, опера, сафари и т.д.) вы имеете дело практически со всеми известными версиями этих браузеров, а чего стоят версии программы для скачивания браузеров версий 5.5, 6.0, 7.0 и т.д., которые практически несовместимы друг с другом, а ребро так и вообще некий непонятный зверь. Гарантии надежности, даже самые простые вы давать не можете.

Теперь, когда мы определились с терминами скажу свое слово относительно фреймворков. Честно говоря лично мне в данный момент они кажуться чем-то странным и ненужным, но требование объективного изложения требуют от меня аргументации. Что ж попробуем.

Принцип работы Backend-ориентированного приложения

  • Все приложение разделяется на набор «экранов», выполняющих небольшую, но законченную функцию
  • Представление (HTML) каждого такого экрана формируется на бэкенде, в том числе вспомогательные окна, сообщения и т.д. (тут кстати возможна простая локализация)
  • Динамика описывается в виде сценариев JavaScript и описывает только конкретный «экран». Код нескольких «экранов» разделен на уровне JavaScript файлов
  • Клиент запрашивает такой экран вместе с необходимыми представлениями и дополнительным программным кодом, обеспечивающим динамику
  • ВСЯ сложная обработка обеспечивается на бэкенде и запрашивается представлением посредством AJAX запросов

Принцип работы Frontend-ориентированного приложения

  • Бэкенд обеспечивает только отдачу статического содержимого и обработку запросов к источникам данных (БД, …)
  • Все представления (в том числе отображаемый HTML) формируется в процессе отображения данных в браузере, что вызывает необходимость переноса таких вещей как модель и контроллер фактически в код представления на JavaScript
  • После того, как клиент получил статику и сформировал представления на стороне клиента, AJAX запросы к серверу делаются исключительно при необходимости работы с источником данных

Собственно, исходя из всего вышеизложенного вытекает инструментарий.

Для Backend-ориентированных:

  • J2EE, Spring MVC, JSP – для бэкенда
  • Twitter Bootstrap, jQuery – для динамики фронтенда

Большего не нужно, этого вполне хватает для разработки качественных backend-ориентированных приложений.

Для frontend-ориентированных

  • Любой Web-сервер – для отдачи статики не важно, какой у вас там сервер, хоть с локальной файловой системы запускайтесь
  • %любой JavaScript фреймворк% – любой из новомодных а потому еще сырых. Выбирайте любой
  • Иногда вам все же понадобиться что-то, работающее с базой данных. Конечно если вы не используете какой-нибудь MongoDB у которого есть REST-интерфейс

На этом все, можете писать комментарии – по ходу пьессы буду дополнять сий опус.