Как объединить похожие мультипакетные проекты в го

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

Проект состоит из трех пакетов:

  1. Библиотека
  2. Исполняемый файл компилятора, который выводит код, необходимый для импорта библиотеки
  3. Исполняемый файл утилиты, который использует код, сгенерированный #2 и ссылки с #1

Большое раздражение при перемещении изменений вперед и назад - это безвозмездные различия в путях импорта. Мы в основном должны редактировать каждую версию import "github.com/companyA/whatever" в import "companyB.com/whatever", Конечно, эти проблемы исчезли бы с (удушьем) относительными путями импорта. Если мы прибегнем к такой ереси, наш компилятор может просто жестко закодировать абсолютный путь импорта в сгенерированном коде, чтобы изолировать конечных пользователей от пути импорта библиотеки. Это также потребовало бы только одного бесплатного различия в исходных деревьях (строка в компиляторе, который выводит операторы импорта), а не связку.

Но в любом случае я знаю, что относительные пути импорта плохие - это сложная ситуация. Я знаю, что это похоже на такие вопросы, как этот или этот, потому что ответ просто попросить конечных пользователей создать каталог под названием companyB.com и клонировать что-то из companyA туда просто летать не собираются по практическим и политическим причинам.

Я уже знаю, что go не очень хорошо справляется с этим сценарием, поэтому я также не прошу волшебную пулю, чтобы заставить go справиться с тем, чего не может. Еще одна вещь, которая, к сожалению, не полетит, это попросить клиентов curl whatever | sh, поскольку это рассматривается как слишком большая ответственность (считается "обучение клиентов делать опасные вещи"). Может быть, мы могли бы отказаться go get и пусть каждый клонирует какое-то нейтральное не-DNS-имя под $GOPATH/src, но нам нужно было бы сделать это без "дня флага", когда код неожиданно ломается, если он находится не в том месте.

У меня вопрос: успешно ли кто-нибудь объединял проекты типа SDK с существующими конечными пользователями, и если да, то как вы это делали, что работало, а что нет? Вы на самом деле избегали относительных путей импорта или грубых GOPATH взлом, а если так, то стоило ли это? Какие механизмы вы использовали (переменные среды, файлы конфигурации, .project-config файлы в текущем рабочем каталоге, злоупотребляя vendor каталог, пакеты генерации кода, которые вычисляют их абсолютный путь импорта во время компиляции), чтобы сделать это гладко? Вы только что запутались с огромным количеством sed или, может быть gofmt -r? Есть ли хитрости, связанные с умным использованием .gitattributes или же go generate переписать пути импорта при оформлении заказа / регистрации?

1 ответ

Объединить их довольно просто - перекрестное слияние, чтобы они все совпадали, выберите один (или создайте новый) в качестве канонического источника правды, затем перенесите все ссылки на канонический импорт и сделайте все будущие обновления там.

Вероятность возникает здесь:

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

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

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

Другие вопросы по тегам