среда, 28 апреля 2021 г.

Обзор файла go.mod

Каждый модуль Go определяется файлом go.mod, который описывает свойства модуля, включая его зависимости от других модулей и от версий Go.

Эти свойства включают:

  • Путь к текущему модулю. Это должно быть место, из которого модуль может быть загружен инструментами Go, например расположение репозитория кода модуля. Он служит уникальным идентификатором в сочетании с номером версии модуля. Это также префикс пути к пакету для всех пакетов в модуле.
  • Минимальная версия Go, необходимая для текущего модуля.
  • Список минимальных версий других модулей, необходимых для текущего модуля.
  • Инструкции, необязательно, для замены необходимого модуля другой версией модуля или локальным каталогом, или для исключения определенной версии необходимого модуля.

Go создает файл go.mod, когда вы запускаете команду go mod init. В следующем примере создается файл go.mod, устанавливая путь к модулю модуля на example.com/mymodule:

$ go mod init example.com/mymodule

Используйте команды go для управления зависимостями. Команды гарантируют, что требования, описанные в вашем файле go.mod, остаются согласованными, а содержимое вашего файла go.mod является действительным. Эти команды включают команды go get and go mod tidy и go mod edit.

Вы можете получить справку из командной строки, набрав go help имя-команды, как в случае с go help mod tidy.

Пример

Файл go.mod включает директивы, показанные в следующем примере. Они описаны в этом посте.

module example.com/mymodule

go 1.14

require (
    example.com/othermodule v1.2.3
    example.com/thismodule v1.2.3
    example.com/thatmodule v1.2.3
)

replace example.com/thatmodule => ../thatmodule
exclude example.com/thismodule v1.3.0

module

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

Синтаксис

module module-path

module-path

Путь к модулю модуля, обычно это расположение репозитория, из которого модуль может быть загружен инструментами Go. Для версий модуля v2 и более поздних это значение должно заканчиваться основным номером версии, например /v2.

Примеры

В следующих примерах example.com заменяется доменом репозитория, из которого можно загрузить модуль.

  • Объявление модуля для модуля v0 или v1:

    module example.com/mymodule
    

  • Путь к модулю для модуля v2:

    module example.com/mymodule/v2
    

Заметки

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

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

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

Например, если вы разрабатываете в каталоге stringtools, ваш временный путь к модулю может быть example.com/stringtools, как в следующем примере:

go mod init example.com/stringtools

go

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

Синтаксис

go minimum-go-version

minimum-go-version

Минимальная версия Go, необходимая для компиляции пакетов в этом модуле.

Примеры

Модуль должен работать на Go версии 1.14 или новее:

go 1.14

Заметки

Директива go изначально предназначалась для поддержки обратно несовместимых изменений языка Go. С момента появления модулей несовместимых языковых изменений не было, но директива go по-прежнему влияет на использование новых языковых функций:

  • Для пакетов в модуле компилятор отклоняет использование языковых функций, представленных после версии, указанной в директиве go. Например, если у модуля есть директива go 1.12, его пакеты могут не использовать числовые литералы, такие как 1_000_000, которые были введены в Go 1.13.
  • Если более старая версия Go собирает один из пакетов модуля и обнаруживает ошибку компиляции, в сообщении об ошибке указывается, что модуль был написан для более новой версии Go. Например, предположим, что у модуля есть версия 1.13, а в пакете используется числовой литерал 1_000_000. Если этот пакет собран с Go 1.12, компилятор отмечает, что код написан для Go 1.13.

Кроме того, команда go изменяет свое поведение в зависимости от версии, указанной в директиве go. Это имеет следующие эффекты:

  • В версии 1.14 или выше может быть включен автоматический вендоринг. Если файл vendor/modules.txt присутствует и согласуется с go.mod, нет необходимости явно использовать флаг -mod=vendor.
  • В версии 1.16 и выше шаблон пакетов all соответствует только пакетам, транзитивно импортированным пакетами и тестами в основном модуле. Это тот же набор пакетов, который оставлен go mod vendor с момента появления модулей. В более низких версиях all также включает пакеты тестов, импортированных пакетами в основном модуле, тесты этих пакетов и т. д.

Файл go.mod может содержать не более одной директивы go. Большинство команд добавят директиву go с текущей версией Go, если она отсутствует.

require

Объявляет модуль как зависимость, требуемую текущим модулем, указывая минимальную требуемую версию модуля.

Синтаксис

require module-path module-version

module-path

Путь к модулю модуля, обычно представляет собой объединение домена репозитория исходного кода модуля и имени модуля. Для версий модуля v2 и более поздних это значение должно заканчиваться основным номером версии, например /v2.

module-version

Версия модуля. Это может быть либо номер версии релиза, например v1.2.3, либо номер псевдо-версии, сгенерированный Go, например v0.0.0-20200921210052-fa0125251cc4.

Примеры

Требование релизной версии v1.2.3:

require example.com/othermodule v1.2.3

Требование версии, еще не имеющей тега в своем репозитории, с использованием номера псевдоверсии, сгенерированного инструментами Go:

require example.com/othermodule v0.0.0-20200921210052-fa0125251cc4

Заметки

Когда вы запускаете команду go, такую как go get, Go вставляет требуемые директивы для каждого модуля, содержащего импортированные пакеты. Когда модуль еще не имеет тега в своем репозитории, Go присваивает номер псевдоверсии, который он генерирует при запуске команды.

Вы можете заставить Go потребовать модуль из места, отличного от его репозитория, с помощью директивы replace.

Дополнительные сведения о номерах версий в посте нумерация версий модулей.

Дополнительные сведения об управлении зависимостями.

replace

Заменяет содержимое модуля определенной версии (или всех версий) другой версией модуля или локальным каталогом. Инструменты Go будут использовать путь замены при разрешении зависимости.

Синтаксис

replace module-path [module-version] => replacement-path [replacement-version]

module-path

Путь к заменяемому модулю.

module-version

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

replacement-path

Путь, по которому Go должен искать нужный модуль. Это может быть путь к модулю или путь к каталогу в файловой системе, локальному для заменяющего модуля. Если это путь к модулю, вы должны указать значение версии для замены. Если это локальный путь, вы не можете использовать значение версии для замены.

replacement-version

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

Примеры

Замена форком репозитория модуля

В следующем примере любая версия example.com/othermodule заменяется указанным форком ее кода.

require example.com/othermodule v1.2.3

replace example.com/othermodule => example.com/myfork/othermodule v1.2.3-fixed

Когда вы заменяете один путь модуля другим, не меняйте операторы импорта для пакетов в модуле, который вы заменяете.

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

Замена на другой номер версии

В следующем примере указывается, что версия v1.2.3 должна использоваться вместо любой другой версии модуля.

require example.com/othermodule v1.2.2

replace example.com/othermodule => example.com/othermodule v1.2.3

В следующем примере версия модуля v1.2.5 заменяется версией v1.2.3 того же модуля.

replace example.com/othermodule v1.2.5 => example.com/othermodule v1.2.3

Замена местным кодом

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

require example.com/othermodule v1.2.3

replace example.com/othermodule => ../othermodule

В следующем примере указано, что локальный каталог должен использоваться только для замены v1.2.5.

require example.com/othermodule v1.2.5

replace example.com/othermodule v1.2.5 => ../othermodule

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

Заметки

Используйте директиву replace, чтобы временно заменить значение пути к модулю другим значением, если вы хотите, чтобы Go использовал другой путь для поиска источника модуля. Это приводит к перенаправлению поиска модуля Go в место замены. Вам не нужно изменять пути импорта пакетов, чтобы использовать путь замены.

Используйте директивы exclude и replace для управления разрешением зависимостей во время сборки при сборке текущего модуля. Эти директивы игнорируются в модулях, зависящих от текущего модуля.

Директива replace может быть полезна в следующих ситуациях:

  • Вы разрабатываете новый модуль, кода которого еще нет в репозитории. Вы хотите протестировать с клиентами, использующими локальную версию.
  • Вы определили проблему с зависимостью, клонировали репозиторий зависимости и тестируете исправление с помощью локального репозитория.

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

Дополнительные сведения о номерах версий в посте нумерация версий модулей.

exclude

Задает модуль или версию модуля, которую необходимо исключить из графа зависимостей текущего модуля.

Синтаксис

exclude module-path module-version

module-path

Путь к модулю исключаемого модуля.

module-version

Конкретная версия, которую нужно исключить.

Пример

Исключить example.com/theirmodule версии v1.3.0

exclude example.com/theirmodule v1.3.0

Заметки

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

Используйте директивы exclude и replace для управления разрешением зависимостей во время сборки при сборке текущего модуля (основного модуля, который вы создаете). Эти директивы игнорируются в модулях, зависящих от текущего модуля.

Вы можете использовать команду go mod edit, чтобы исключить модуль, как в следующем примере.

go mod edit -exclude=example.com/theirmodule@v1.3.0

Дополнительные сведения о номерах версий в посте нумерация версий модулей.


Читайте также:


понедельник, 26 апреля 2021 г.

Нумерация версий модуля

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

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

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

Смотрите также:

Когда вы используете внешние пакеты в своем коде, вы можете управлять этими зависимостями с помощью инструментов Go.

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

Выпущенный модуль публикуется с номером версии в семантической модели управления версиями, как показано на следующем рисунке:

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

    • Модуль в разработке
    • Автоматический номер псевдоверсии, v0.x.x
    • Сигнализирует о том, что модуль все еще находится в разработке и нестабилен. Этот релиз не дает никаких гарантий обратной совместимости или стабильности.
    • Основная (major) версия
    • v1.x.x
    • Сообщает об изменениях общедоступного API, несовместимых с предыдущими версиями. Этот релиз не дает никаких гарантий, что он будет обратно совместим с предыдущими основными версиями.
    • Минорная (minor) версия
    • vx.4.x
    • Сообщает об изменениях общедоступного API с обратной совместимостью. Этот релиз гарантирует обратную совместимость и стабильность.
    • Версия (patch) исправлений
    • vx.x.1
    • Сообщает об изменениях, которые не влияют на общедоступный API модуля или его зависимости. Этот релиз гарантирует обратную совместимость и стабильность.
    • Предварительная версия
    • vx.x.x-beta.2
    • Сигнализирует о том, что это предварительная веха, например, альфа или бета. Этот релиз не дает никаких гарантий стабильности.

В разработке

Сигнализирует о том, что модуль все еще находится в разработке и нестабилен. Этот релиз не дает никаких гарантий обратной совместимости или стабильности.

Номер версии может принимать одну из следующих форм:

  • Номер псевдоверсии
    v0.0.0-20170915032832-14c0d48ead0c
  • Номер v0
    v0.x.x

Номер псевдоверсии

Если модуль не был помечен (не имеет тега) в своем репозитории, инструменты Go сгенерируют номер псевдоверсии для использования в файле go.mod кода, который вызывает функции в модуле.

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

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

Номер псевдоверсии состоит из трех частей, разделенных тире, как показано в следующей форме:

Синтаксис

baseVersionPrefix-timestamp-revisionIdentifier

Части

  • baseVersionPrefix (vX.0.0 или vX.Y.Z-0) - значение, полученное либо из тега семантической версии, предшествующего редакции, либо из vX.0.0, если такого тега нет.
  • timestamp (yymmddhhmmss) - время создания ревизии в формате UTC. В Git это время коммита, а не время автора.
  • revisionIdentifier (abcdefabcdef) - это 12-символьный префикс хэша коммита или, в Subversion, номер версии, дополненный нулями.

Номер v0

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

Хотя версию v0 можно использовать в производстве, она не дает никаких гарантий стабильности или обратной совместимости. Кроме того, версии v1 и более поздние могут нарушать обратную совместимость для кода, использующего версии v0. По этой причине разработчик функций, использующих код в модуле v0, несет ответственность за адаптацию к несовместимым изменениям, пока не будет выпущена версия v1.

Предварительная версия

Сигнализирует о том, что это предварительная веха, например альфа или бета. Этот релиз не дает никаких гарантий стабильности.

Пример

vx.x.x-beta.2

Разработчик модуля может использовать идентификатор предварительной версии с любой комбинацией major.minor.patch, добавив дефис и идентификатор предварительной версии.

Минорная версия

Сообщает об обратно совместимых изменениях в общедоступном API модуля. Этот релиз гарантирует обратную совместимость и стабильность.

Пример

vx.4.x

Эта версия изменяет общедоступный API модуля, но не таким образом, чтобы нарушать вызывающий код. Это может включать изменения собственных зависимостей модуля или добавление новых функций, методов, полей структур или типов.

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

Версия патча

Сообщает об изменениях, которые не влияют на общедоступный API модуля или его зависимости. Этот релиз гарантирует обратную совместимость и стабильность.

Пример

vx.x.1

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

Основная версия

Сообщает о несовместимых изменениях в общедоступном API модуля. Этот релиз не дает никаких гарантий, что он будет обратно совместим с предыдущими основными версиями.

Пример

v1.x.x

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

Обратите внимание: поскольку версия 0 не дает никаких гарантий стабильности или обратной совместимости, разработчик, обновляющий модуль с v0 до v1, несет ответственность за адаптацию к изменениям, нарушающим обратную совместимость.

Разработчик модуля должен увеличивать это число после v1 только при необходимости, потому что обновление версии представляет собой серьезное нарушение работы разработчиков, код которых использует функцию в обновленном модуле. Это нарушение включает обратно несовместимые изменения в общедоступном API, а также необходимость для разработчиков, использующих модуль, обновлять путь к пакету везде, где они импортируют пакеты из модуля.

Обновление основной версии до номера выше v1 также будет иметь новый путь к модулю. Это потому, что к пути к модулю будет добавлен основной номер версии, как в следующем примере:

module example.com/mymodule/v2 v2.0.0

Обновление основной версии делает этот модуль новым с историей, отдельной от предыдущей версии модуля.


Читайте также:


пятница, 23 апреля 2021 г.

Публикация модуля в Golang

Если вы хотите сделать модуль доступным для других разработчиков, вы публикуете его, чтобы он стал видимым для инструментов Go. После публикации модуля разработчики, импортирующие его пакеты, смогут разрешить зависимость от модуля, выполнив такие команды, как go get.

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

Шаги публикации

Чтобы опубликовать модуль, выполните следующие действия.

1. Откройте командную строку и перейдите в корневой каталог вашего модуля в локальном репозитории.

2. Запустите go mod tidy, которая удалит все зависимости, которые модуль мог накопить, которые больше не нужны.

$ go mod tidy

3. Запустите go test ./... последний раз, чтобы убедиться, что все работает.

Это запускает модульные (юнит) тесты, которые вы написали с помощью Go фреймворка testing.

$ go test ./...
ok      example.com/mymodule       0.015s

4. Отметьте проект новым номером версии с помощью команды git tag.

В качестве номера версии используйте номер, который сигнализирует пользователям о характере изменений в этом выпуске.

$ git commit -m "mymodule: changes for v0.1.0"
$ git tag v0.1.0

5. Отправьте новый тег в исходный репозиторий.

$ git push origin v0.1.0

6. Сделайте модуль доступным, выполнив команду go list, чтобы запросить Go обновить его индекс модулей с информацией о модуле, который вы публикуете.

Перед командой укажите инструкцию для установки переменной среды GOPROXY на прокси-сервер Go. Это гарантирует, что ваш запрос достигнет прокси.

$ GOPROXY=proxy.golang.org go list -m example.com/mymodule@v0.1.0

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

$ go get example.com/mymodule@v0.1.0


Читайте также:


четверг, 22 апреля 2021 г.

Разработка обновления основной версии

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

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

Рекомендации по обновлению основной версии

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

  • Сообщите своим пользователям, что выпуск новой основной версии означает для вас поддержку предыдущих основных версий.
  • Предыдущие версии устарели? Поддерживаются как раньше? Будете ли вы поддерживать предыдущие версии, в том числе с исправлениями ошибок?
  • Будьте готовы взять на себя обслуживание двух версий: старой и новой. Например, если вы исправляете ошибки в одной, вы часто будете переносить эти исправления в другой.
  • Помните, что новая основная версия - это новый модуль с точки зрения управления зависимостями. Вашим пользователям необходимо будет выполнить обновление, чтобы использовать новый модуль после выпуска, а не просто выполнить обновление.
    Это потому, что в новой основной версии путь к модулю отличается от пути к предыдущей основной версии. Например, для модуля, чей путь к модулю - example.com/mymodule, версия v2 будет иметь путь к модулю example.com/mymodule/v2.
  • При разработке новой основной версии вы также должны обновить пути импорта везде, где код импортирует пакеты из нового модуля. Пользователи вашего модуля также должны обновить свои пути импорта, если они хотят перейти на новую основную версию.

Разветвление для основного релиза

Самый простой подход к работе с исходным кодом при подготовке к разработке новой основной версии - это разветвление репозитория на последней версии предыдущей основной версии.

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

$ cd mymodule
$ git checkout -b v2
Switched to a new branch "v2"

Схема, показывающая репозиторий, ответвленный от master к v2:

После разветвления исходного кода вам необходимо внести следующие изменения в исходные файлы для вашей новой версии:

  • В файле go.mod новой версии добавьте номер новой основной версии к пути к модулю, как в следующем примере:
    • Существующая версия: example.com/mymodule
    • Новая версия: example.com/mymodule/v2
  • В коде Go обновите каждый импортированный путь к пакету, в который вы импортируете пакет из модуля, добавив номер основной версии к части пути к модулю.
    • Старый оператор импорта: import "example.com/mymodule/package1"
    • Новый оператор импорта: import "example.com/mymodule/v2/package1"

Читайте также:


среда, 21 апреля 2021 г.

Управление исходным кодом модуля

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

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

Go поддерживает следующие репозитории для публикации модулей: Git, Subversion, Mercurial, Bazaar и Fossil.

Как инструменты Go находят ваш опубликованный модуль

В децентрализованной системе Go для публикации модулей и получения их кода вы можете опубликовать свой модуль, оставив код в своем репозитории. Инструменты Go полагаются на правила именования, в которых есть пути к репозиториям и теги репозитория, указывающие имя модуля и номер версии. Когда ваш репозиторий соответствует этим требованиям, код вашего модуля может быть загружен из вашего репозитория с помощью инструментов Go, таких как команда go get.

Когда разработчик использует команду go get для получения исходного кода для пакетов, импортируемых его кодом, она выполняет следующие действия:

  1. Из операторов импорта в исходном коде Go команда go get определяет путь к модулю в пути к пакету.
  2. Используя URL-адрес, полученный из пути к модулю, команда находит источник модуля на прокси-сервере модуля или непосредственно в его репозитории.
  3. Находит источник для версии модуля для загрузки, сопоставляя номер версии модуля с тегом репозитория, чтобы обнаружить код в репозитории. Если номер версии для использования еще не известен, переходит по ссылке и находит последнюю версию релиза.
  4. Получает исходный код модуля и загружает его в локальный кеш модуля разработчика.

Организация кода в репозитории

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

На следующей диаграмме показана исходная иерархия для простого модуля с двумя пакетами.

Ваш модуль должен включать следующие файлы:

  • LICENSE
    Лицензия для модуля.
  • go.mod
    Описывает модуль, включая его путь к модулю (фактически, его имя) и его зависимости.
    Путь к модулю будет указан в директиве модуля, например:

    module example.com/mymodule
    

    Хотя вы можете редактировать этот файл, большая часть его поддерживается командами go.
  • go.sum
    Содержит криптографические хэши, которые представляют зависимости модуля. Инструменты Go используют эти хэши для аутентификации загруженных модулей, пытаясь подтвердить подлинность загруженного модуля. Если это подтверждение не удалось, Go отобразит ошибку безопасности.
    Файл будет пустым или будет отсутствовать, если нет зависимостей. Вы не должны редактировать этот файл, кроме как с помощью команды go mod tidy, которая удаляет ненужные записи.
  • Каталоги пакетов и исходные файлы .go.
    Каталоги и файлы .go, которые составляют пакеты и исходные коды Go в модуле.

Из командной строки вы можете создать пустой репозиторий, добавить файлы, которые будут частью вашего первоначального коммита, и выполнить коммит с сообщением. Вот пример использования git:

$ git init
$ git add --all
$ git commit -m "mycode: initial commit"
$ git push

Выбор объема репозитория

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

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

Поддержка одного модуля на репозиторий

Вы можете поддерживать репозиторий, в котором есть исходный код одного модуля. В этой модели вы помещаете файл go.mod в корень репозитория с подкаталогами пакетов, содержащими исходный код Go.

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

Диаграмма, показывающая исходный код отдельного модуля в его репозитории

Поддержка нескольких модулей в одном репозитории

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

Каждый подкаталог, который является корневым каталогом модуля, должен иметь свой собственный файл go.mod.

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

Например, для модуля example.com/mymodules/module1 ниже у вас будет следующее для версии v1.2.3:

  • Путь к модулю: example.com/mymodules/module1
  • Тег версии: module1/v1.2.3
  • Путь к пакету, импортированный пользователем: example.com/mymodules/module1/package1
  • Путь к модулю, указанный в директиве require пользователя: example.com/mymodules/module1 module1/v1.2.3

Читайте также:


понедельник, 19 апреля 2021 г.

Выпуск модуля и рабочий процесс управления версиями

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

Обзор разработки модулей смотрите в посте Разработка и публикация модулей.

Если вы просто хотите использовать внешние пакеты в своем коде, обязательно ознакомьтесь с постом Управление зависимостями.

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

Общие шаги рабочего процесса

Следующая последовательность иллюстрирует шаги рабочего процесса выпуска и управления версиями для примера нового модуля.

  • Начните модуль и организуйте его исходный код, чтобы разработчикам было проще его использовать, а вам - поддерживать.
    Если вы новичок в разработке модулей, ознакомьтесь с Созданием модуля Go.
  • Настройте для написания кода локального клиента, который вызывает функции в неопубликованном модуле.
    Перед публикацией модуля он недоступен для обычного рабочего процесса управления зависимостями с использованием таких команд, как go get. Хороший способ протестировать код вашего модуля на этом этапе - это попробовать его, пока он находится в каталоге, локальном для вашего вызывающего кода.
  • Когда код модуля будет готов для других разработчиков, начните публиковать предварительные версии v0, такие как альфа- и бета-версии.
  • Выпустите версию v0, стабильность которой не гарантируется, но пользователи могут попробовать ее.
  • После публикации вашей версии v0 вы можете (и следует) продолжать выпускать ее новые версии.
    Эти новые версии могут включать исправления ошибок (релизы патчей), дополнения к общедоступному API модуля (минорные релизы) и даже критические изменения. Поскольку релиз v0 не дает никаких гарантий стабильности или обратной совместимости, вы можете вносить критические изменения в его версии.
  • Когда вы готовите стабильную версию, готовую к релизу, вы публикуете предварительные релизы как альфа- и бета-версии.
  • Выпустите v1 как первый стабильный релиз.
    Это первый релиз, в котором говорится о стабильности модуля.
  • В версии v1 продолжайте исправлять ошибки и, при необходимости, вносить дополнения в общедоступный API модуля.
  • Если этого невозможно избежать, опубликуйте ломающие изменения в новой основной версии.

Обновление основной версии - например, с v1.x.x до v2.x.x - может сильно помешать пользователям вашего модуля. Это должно быть последнее средство.

Кодирование неопубликованного модуля

Когда вы начинаете разрабатывать модуль или новую версию модуля, вы еще не опубликовали его. Перед публикацией модуля вы не сможете использовать команды Go для добавления модуля в качестве зависимости. Вместо этого сначала при написании клиентского кода в другом модуле, который вызывает функции в неопубликованном модуле, вам нужно будет ссылаться на копию модуля в локальной файловой системе.

Вы можете ссылаться на модуль локально из файла go.mod клиентского модуля, используя директиву replace в файле go.mod клиентского модуля.

Публикация предварительных версий

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

К номерам предварительной версии добавляется идентификатор предварительной версии.

Вот два примера:

  • v0.2.1-beta.1
  • v1.2.3-alpha

Делая предварительную версию доступной, имейте в виду, что разработчики, использующие предварительную версию, должны будут явно указать ее по версии с помощью команды go get. Это потому, что по умолчанию команда go отдает предпочтение релизным версиям перед предварительными версиями при поиске запрашиваемого модуля. Поэтому разработчики должны получить предварительную версию, явно указав ее, как в следующем примере:

go get example.com/theirmodule@v1.2.3-alpha

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

Публикация первой (нестабильной) версии

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

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

Как и в случае с другими опубликованными версиями, вы можете увеличивать минорную часть и патч часть номера версии v0 по мере внесения изменений в выпуск стабильной версии v1. Например, после выпуска v0.0.0 вы можете выпустить v0.0.1 с первым набором исправлений ошибок.

Вот пример номера версии:

v0.1.3

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

Публикация первой стабильной версии

Ваш первый стабильный релиз будет иметь номер версии v1.x.x. Первый стабильный релиз следует за предварительным релизом и релизом v0, благодаря которым вы получили отзывы, исправили ошибки и стабилизировали модуль для пользователей.

С выпуском v1 вы берете на себя следующие обязательства перед разработчиками, использующими ваш модуль:

  • Они могут перейти на последующие второстепенные (минорные) релизы и релизы исправлений (патч) основной версии, не нарушая собственный код.
  • Вы не будете вносить дальнейшие изменения в общедоступный API модуля, включая его функции и сигнатуры методов, которые нарушают обратную совместимость.
  • Вы не будете удалять экспортированные типы, так как это нарушит обратную совместимость.
  • Будущие изменения в вашем API (например, добавление нового поля в структуру) будут обратно совместимы и будут включены в новый минорный релиз.
  • Исправления ошибок (например, исправления безопасности) будут включены в релиз исправлений или как часть минорного релиза.

Примечание. Хотя ваша первая основная версия может быть релизом v0, версия v0 не дает никаких гарантий стабильности или обратной совместимости. В результате при увеличении от v0 до v1 вам не нужно помнить о нарушении обратной совместимости, потому что релиз v0 не считался стабильным.

Вот пример номера стабильной версии:

v1.0.0

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

Публикация исправлений ошибок

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

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

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

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

В следующем примере v1.0.1 - это релиз исправлений.

Старая версия: v1.0.0

Новая версия: v1.0.1

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

Публикация не-ломающих изменений API

Вы можете внести не-ломающие изменения в общедоступный API вашего модуля и опубликовать эти изменения в релизе минорной версии.

Эта версия изменяет API, но не таким образом, чтобы нарушать вызывающий код. Это может включать изменения собственных зависимостей модуля или добавление новых функций, методов, полей структур или типов. Даже с внесенными в него изменениями этот вид релиза гарантирует обратную совместимость и стабильность для существующего кода, который вызывает функции модуля.

Минорный релиз увеличивает минорную часть номера версии модуля.

В следующем примере v1.1.0 является минорным релизом.

Старая версия: v1.0.1

Новая версия: v1.1.0

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

Публикация ломающих изменений API

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

Релиз основной версии не гарантирует обратной совместимости, как правило, потому, что он включает изменения в общедоступном API модуля, которые нарушили бы код, использующий предыдущие версии модуля.

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

Если для публикации других типов версий требуется по существу пометить код модуля номером версии, публикация обновления основной версии требует дополнительных шагов.

  • Перед началом разработки новой основной версии создайте в своем репозитории место для исходного кода новой версии.
    Один из способов сделать это - создать новую ветку в вашем репозитории, специально предназначенную для новой основной версии и ее последующих минорных версий и версий исправлений.
  • В файле модуля go.mod измените путь к модулю, чтобы добавить новый основной номер версии, как в следующем примере:

    example.com/mymodule/v2
    

    Учитывая, что путь к модулю является идентификатором модуля, это изменение фактически создает новый модуль. Он также изменяет путь к пакету, гарантируя, что разработчики не будут непреднамеренно импортировать версию, нарушающую их код. Вместо этого те, кто хочет обновить, будут явно заменять вхождения старого пути новым.
  • В своем коде измените все пути к пакетам, в которые вы импортируете пакеты в обновляемом модуле, включая пакеты в модуле, который вы обновляете. Вам нужно сделать это, потому что вы изменили путь к модулю.
  • Как и в случае с любым новым выпуском, перед публикацией официального выпуска вам следует публиковать предварительные версии, чтобы получать отзывы и отчеты об ошибках.
  • Опубликуйте новую основную версию, пометив код модуля в своем репозитории, увеличив номер основной версии в теге - например, с v1.5.2 до v2.0.0.

Читайте также:


четверг, 15 апреля 2021 г.

Разработка и публикация модулей в Golang

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

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

  • Рабочий процесс, с помощью которого вы разрабатываете и публикуете модули, со временем обновляя их новыми версиями.
  • Приемы проектирования, которые помогают пользователям модуля понять его и стабильно обновлять до новых версий.
  • Децентрализованная система для публикации модулей и получения их кода. Вы делаете свой модуль доступным для использования другими разработчиками из вашего собственного репозитория и публикуете с номером версии.
  • Система поиска пакетов и браузер документации (pkg.go.dev), в котором разработчики могут найти ваш модуль.
  • Соглашение о нумерации версий модуля, чтобы сообщить разработчикам, использующим ваш модуль, ожидания стабильности и обратной совместимости.
  • Инструменты Go, которые упрощают другим разработчикам управление зависимостями, включая получение исходного кода вашего модуля, обновление и т. д.

Смотрите также

Рабочий процесс разработки и публикации модулей

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

  1. Разработайте и запрограммируйте пакеты, которые будет включать модуль.
  2. Зафиксируйте код в своем репозитории, используя соглашения, которые гарантируют, что он будет доступен другим через инструменты Go.
  3. Опубликуйте модуль, чтобы разработчики могли его обнаружить.
  4. Со временем обновите модуль, добавив в него версии, использующие соглашение о нумерации версий, которое сигнализирует о стабильности каждой версии и обратной совместимости.

Дизайн и развитие

Разработчикам будет легче найти и использовать ваш модуль, если функции и пакеты в нем образуют единое целое. При разработке общедоступного API модуля старайтесь, чтобы его функциональность была сфокусированной и дискретной.

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

Перед публикацией модуля вы можете ссылаться на него в локальной файловой системе с помощью директивы replace. Это упрощает написание клиентского кода, который вызывает функции в модуле, пока модуль все еще находится в разработке.

Децентрализованная публикация

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

После импорта вашего пакета в свой код разработчики используют инструменты Go (включая команду go get), чтобы загрузить код вашего модуля для компиляции. Для поддержки этой модели вы следуете соглашениям, которые позволяют инструментам Go (от имени другого разработчика) извлекать исходный код вашего модуля из вашего репозитория. Например, инструменты Go используют указанный вами путь к модулю вместе с номером версии модуля, который вы используете для маркировки модуля для выпуска, чтобы найти и загрузить модуль для его пользователей.

Обнаружение пакетов

После того, как вы опубликовали свой модуль и кто-то загрузил его с помощью инструментов Go, он станет видимым на сайте обнаружения пакетов Go по адресу pkg.go.dev. Там разработчики могут выполнить поиск по сайту и прочитать документацию.

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

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

Управление версиями

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


Читайте также:


вторник, 13 апреля 2021 г.

Базовый макет для проектов Go приложений

В посте описан базовый макет для проектов приложений Go. Это не официальный стандарт, определенный основной командой разработчиков Go; однако это набор общих исторических и новых шаблонов макета проектов в экосистеме Go. Некоторые из этих шаблонов более популярны, чем другие. Он также имеет ряд небольших улучшений и несколько вспомогательных каталогов, общих для любого достаточно большого реального приложения.

Если вы пытаетесь изучить Go или строите PoC-проект или игрушечный проект для себя, этот макет проекта будет излишним. Начните с чего-нибудь действительно простого (одного файла main.go более чем достаточно). По мере роста вашего проекта имейте в виду, что важно убедиться, что ваш код хорошо структурирован, иначе вы получите беспорядочный код с множеством скрытых зависимостей и глобальным состоянием. Когда над проектом будет работать больше людей, вам понадобится еще больше структуры. Вот когда важно представить общий способ управления пакетами/библиотеками. Когда у вас есть проект с открытым исходным кодом или когда вы знаете, что другие проекты импортируют код из репозитория вашего проекта, тогда важно иметь частные (private) (также известные как internal) пакеты и код. Клонируйте репозиторий, сохраните то, что вам нужно, а все остальное удалите! То, что оно есть, не означает, что вам нужно использовать все это. Ни один из этих шаблонов не используется в каждом отдельном проекте. Даже шаблон vendor не универсален.

С Go 1.14 модули Go наконец-то готовы к производственному использованию. Используйте модули Go, если у вас нет особой причины не использовать их, и если вы это сделаете, вам не нужно беспокоиться о $GOPATH и о том, где вы разместите свой проект. Базовый файл go.mod в репозитории предполагает, что ваш проект размещен на GitHub, но это не является обязательным требованием. Путь к модулю может быть любым.

Этот макет проекта намеренно общий и не пытается навязывать конкретную структуру пакета Go.

Каталоги Go

/cmd

Основные (main) приложения для этого проекта.

Имя каталога для каждого приложения должно соответствовать имени исполняемого файла, который вы хотите иметь (например, /cmd/myapp).

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

Обычно есть небольшая функция main, которая импортирует и вызывает код из каталогов /internal и /pkg и ничего больше.

Примеры:

/internal

Частное приложение и код библиотеки. Это код, который вы не хотите, чтобы другие импортировали в свои приложения или библиотеки. Обратите внимание, что этот шаблон макета применяется самим компилятором Go. Вы не ограничены внутренним каталогом верхнего уровня. У вас может быть более одного внутреннего каталога на любом уровне дерева вашего проекта.

При желании вы можете добавить немного дополнительной структуры к своим внутренним пакетам, чтобы разделить общий и не общий внутренний код. Это не обязательно (особенно для небольших проектов), но хорошо иметь визуальные подсказки, показывающие предполагаемое использование пакета. Фактический код вашего приложения может находиться в каталоге /internal/app (например, /internal/app/myapp), а код, совместно используемый этими приложениями, - в каталоге /internal/pkg (например, /internal/pkg/myprivlib).

Примеры:

/pkg

Код библиотеки, который можно использовать внешними приложениями (например, /pkg/mypubliclib). Другие проекты будут импортировать эти библиотеки, ожидая, что они будут работать, поэтому подумайте дважды, прежде чем что-то здесь помещать) Обратите внимание, что internal каталог - лучший способ гарантировать, что ваши частные пакеты не будут импортированы, потому что это выполняется Go. Каталог /pkg по-прежнему является хорошим способом явным образом сообщить, что код в этом каталоге безопасен для использования другими.

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

Примеры:

Каталог /pkg, это распространенный шаблон макета, но он не является общепринятым, и некоторые в сообществе Go не рекомендуют его.

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

/vendor

Зависимости приложений (управляемые вручную или с помощью вашего любимого инструмента управления зависимостями, такого как новая встроенная функция модулей Go). Команда go mod vendor создаст для вас каталог /vendor. Обратите внимание, что вам может потребоваться добавить флаг -mod=vendor в вашу команду сборки go, если вы не используете Go 1.14, где он включен по умолчанию.

Не фиксируйте зависимости своего приложения, если вы создаете библиотеку.

Обратите внимание, что начиная с версии 1.13 Go также включает функцию прокси-сервера модуля (по умолчанию используется https://proxy.golang.org в качестве прокси-сервера модуля). Если это так, то каталог vendor вам вообще не понадобится.

Каталоги приложений-служб

/api

Спецификации OpenAPI/Swagger, файлы схемы JSON, файлы определения протокола.

Примеры:

Каталоги веб-приложений

/web

Компоненты, специфичные для веб-приложений: статические веб-ресурсы, серверные шаблоны и SPA.

Общие каталоги приложений

/configs

Шаблоны файлов конфигурации или конфигурации по умолчанию.

Поместите сюда файлы шаблона confd или consul-template.

/init

Конфигурации системного init (systemd, upstart, sysv) и диспетчера/супервизора процессов (runit, supervisord).

/scripts

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

Эти сценарии сохраняют Makefile корневого уровня маленьким и простым (например, https://github.com/hashicorp/terraform/blob/main/Makefile).

Примеры:

/build

Сборка и непрерывная интеграция.

Поместите конфигурации и сценарии вашего облака (AMI), контейнера (Docker), ОС (deb, rpm, pkg) в каталог /build/package.

Поместите свои конфигурации и сценарии CI (travis, circle, drone) в каталог /build/ci. Обратите внимание, что некоторые инструменты CI (например, Travis CI) очень разборчивы в расположении своих файлов конфигурации. Попробуйте поместить файлы конфигурации в каталог /build/ci, связав их с местом, где их ожидают инструменты CI (если возможно).

/deployments

Конфигурации и шаблоны развертывания IaaS, PaaS, системы оркестрации и контейнеров (docker-compose, kubernetes/helm, mesos, terraform, bosh). Обратите внимание, что в некоторых репозиториях (особенно в приложениях, развернутых с помощью kubernetes) этот каталог называется /deploy.

/test

Дополнительные внешние тестовые приложения и тестовые данные. Не стесняйтесь структурировать каталог /test как хотите. Для более крупных проектов имеет смысл создать подкаталог данных. Например, у вас может быть /test/data или /test/testdata, если вам нужно, чтобы Go игнорировал содержимое этого каталога. Обратите внимание, что Go также игнорирует каталоги или файлы, начинающиеся с "." или "_", чтобы у вас было больше гибкости в том, как вы называете каталог тестовых данных.

Пример:

Другие каталоги

/docs

Дизайнерские и пользовательские документы (в дополнение к документации, созданной с помощью godoc).

Примеры:

/tools

Вспомогательные инструменты для этого проекта. Обратите внимание, что эти инструменты могут импортировать код из каталогов /pkg и /internal.

Примеры:

/examples

Примеры для ваших приложений и/или публичных библиотек.

Примеры:

/third_party

Внешние вспомогательные инструменты, код fork'ов и другие сторонние утилиты (например, Swagger UI).

/githooks

Хуки Git.

/assets

Другие ресурсы для вашего репозитория (изображения, логотипы и т. д.).

/website

Это место для размещения данных веб-сайта вашего проекта, если вы не используете GitHub pages.

Пример:

Каталоги, которых лучше не иметь

/src

В некоторых проектах Go есть папка src, но обычно это происходит, когда разработчики приходят из мира Java, где это общий шаблон. Если вы можете помочь себе, постарайтесь не применять этот шаблон Java. Вы действительно не хотите, чтобы ваш код Go или проекты Go выглядели как Java.

Не путайте каталог /src уровня проекта с каталогом /src, который Go использует для своих рабочих пространств. Переменная среды $GOPATH указывает на вашу (текущую) рабочую область (по умолчанию она указывает на $HOME/ go в системах, отличных от Windows). Это рабочее пространство включает каталоги верхнего уровня /pkg, /bin и /src. Ваш фактический проект оказывается подкаталогом в /src, поэтому, если у вас есть каталог /src в вашем проекте, путь к проекту будет выглядеть так: /some/path/to/workspace/src/your_project/src/your_code.go. Обратите внимание, что в Go 1.11 можно иметь свой проект за пределами GOPATH, но это еще не означает, что использовать этот шаблон макета - хорошая идея.


Читайте также:


воскресенье, 11 апреля 2021 г.

Создание модуля в Golang: скомпилируйте и установите приложение

В этом посте вы изучите пару новых команд go. Хотя команда go run является полезным ярлыком для компиляции и запуска программы, когда вы часто вносите изменения, она не создает двоичный исполняемый файл.

В этом разделе представлены две дополнительные команды для сборки кода:

  • Команда go build компилирует пакеты вместе с их зависимостями, но не устанавливает результаты.
  • Команда go install компилирует и устанавливает пакеты.

Примечание. Этот раздел является частью руководства, состоящего из нескольких частей, который начинается с создания модуля Go.

1. Из командной строки в каталоге hello запустите команду go build, чтобы скомпилировать код в исполняемый файл.

$ go build

2. Из командной строки в каталоге hello запустите новый исполняемый файл hello, чтобы убедиться, что код работает.

Обратите внимание, что ваш результат может отличаться в зависимости от того, изменили ли вы код greetings.go после его тестирования.

В Linux или Mac:

$ ./hello
map[Darrin:Great to see you, Darrin! Gladys:Hail, Gladys! Well met! Samantha:Hail, Samantha! Well met!]

В Windows:

$ hello.exe
map[Darrin:Great to see you, Darrin! Gladys:Hail, Gladys! Well met! Samantha:Hail, Samantha! Well met!]

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

Далее вы установите исполняемый файл, чтобы его можно было запустить, не указывая путь к нему.

3. Найдите путь установки Go, по которому команда go установит текущий пакет.

Вы можете узнать путь установки, выполнив команду go list, как в следующем примере:

$ go list -f '{{.Target}}'

Например, в выводе команды может быть указано /home/gopher/bin/hello, что означает, что двоичные файлы устанавливаются в /home/gopher/bin. Этот установочный каталог понадобится вам на следующем шаге.

4. Добавьте установочный каталог Go в путь к системной оболочке.

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

В Linux или Mac выполните следующую команду (действует только в текущей сессии пользователя, для постоянного изменения следует использовать файл .bashrc):

$ export PATH=$PATH:/путь/к/вашему/установочному/каталогу

В Windows выполните следующую команду:

$ set PATH=%PATH%;C:\путь\к\вашему\установочному\каталогу

В качестве альтернативы, если у вас уже есть каталог $HOME/bin в пути к оболочке и вы хотите установить туда свои программы Go, вы можете изменить цель установки, установив переменную GOBIN с помощью команды go env:

$ go env -w GOBIN=/путь/к/вашему/bin

или же

$ go env -w GOBIN=C:\путь\к\вашему\bin

5. После обновления пути к оболочке (shell path) запустите команду go install, чтобы скомпилировать и установить пакет.

$ go install

6. Запустите приложение, просто набрав его имя. Чтобы сделать это интересным, откройте новую командную строку и запустите исполняемый файл hello с именем в другом каталоге.

$ hello
map[Darrin:Hail, Darrin! Well met! Gladys:Great to see you, Gladys! Samantha:Hail, Samantha! Well met!]

На этом руководство по созданию модуля Go завершено.


Читайте также:


Создание модуля в Golang: добавить тест

Теперь, когда вы привели свой код в стабильное состояние, добавьте тест. Тестирование кода во время разработки может выявить ошибки, которые обнаруживаются при внесении вами изменений. В этом посте вы добавите тест для функции Hello.

Примечание. Этот раздел является частью руководства, состоящего из нескольких частей, которое начинается с создания модуля Go.

Встроенная поддержка модульного тестирования Go упрощает тестирование на ходу. В частности, используя соглашения об именах, Go пакет testing и команду go test, вы можете быстро писать и выполнять тесты.

1. В каталоге greetings создайте файл с именем greetings_test.go.

Завершение имени файла _test.go сообщает команде go test, что этот файл содержит тестовые функции.

2. В greetings_test.go вставьте следующий код и сохраните файл.

package greetings

import (
    "testing"
    "regexp"
)

// TestHelloName вызывает greetings.Hello с именем, проверка
// для допустимого возвращаемого значения.
func TestHelloName(t *testing.T) {
    name := "Gladys"
    want := regexp.MustCompile(`\b`+name+`\b`)
    msg, err := Hello("Gladys")
    if !want.MatchString(msg) || err != nil {
        t.Fatalf(`Hello("Gladys") = %q, %v, want match for %#q, nil`, msg, err, want)
    }
}

// TestHelloEmpty вызывает greetings.Hello с пустой строкой,
// проверка на наличие ошибки.
func TestHelloEmpty(t *testing.T) {
    msg, err := Hello("")
    if msg != "" || err == nil {
        t.Fatalf(`Hello("") = %q, %v, want "", error`, msg, err)
    }
}

В этом коде вы:

  • Реализуете тестовые функции в том же пакете, что и тестируемый код.
  • Создаете две тестовые функции для проверки функции greetings.Hello. Имена тестовых функций имеют вид TestName, где Name что-то говорит о конкретном тесте. Кроме того, тестовые функции принимают в качестве параметра указатель на тип testing.T пакета testing. Вы используете методы этого параметра для создания отчетов и ведения журнала из вашего теста.
  • Реализуете два теста:
    TestHelloName вызывает функцию Hello, передавая значение имени, с которым функция должна иметь возможность возвращать допустимое ответное сообщение. Если вызов возвращает сообщение об ошибке или неожиданное ответное сообщение (которое не включает имя, которое вы передали), вы используете метод Fatalf параметра t, чтобы вывести сообщение на консоль и завершить выполнение.
    TestHelloEmpty вызывает функцию Hello с пустой строкой. Этот тест разработан, чтобы подтвердить, что ваша обработка ошибок работает. Если вызов возвращает непустую строку или нет ошибки, вы используете метод Fatalf параметра t для вывода сообщения на консоль и завершения выполнения.

3. В командной строке в каталоге greetings запустите команду go test, чтобы выполнить тест.

Команда go test выполняет тестовые функции (имена которых начинаются с Test) в тестовых файлах (имена которых заканчиваются на _test.go). Вы можете добавить флаг -v, чтобы получить подробный вывод, в котором перечислены все тесты и их результаты.

Тесты должны пройти.

$ go test
PASS
ok      example.com/greetings   0.364s

$ go test -v
=== RUN   TestHelloName
--- PASS: TestHelloName (0.00s)
=== RUN   TestHelloEmpty
--- PASS: TestHelloEmpty (0.00s)
PASS
ok      example.com/greetings   0.372s

4. Сломайте функцию greetings.Hello, чтобы просмотреть неудачный тест.

Тестовая функция TestHelloName проверяет возвращаемое значение для имени, которое вы указали в качестве параметра функции Hello. Чтобы просмотреть неудачный результат теста, измените функцию greetings.Hello так, чтобы она больше не включала имя.

В greetings/greetings.go вставьте следующий код вместо функции Hello. Обратите внимание, что выделенные строки изменяют значение, возвращаемое функцией, как если бы аргумент имени был случайно удален.

// Hello возвращает приветствие для указанного человека.
func Hello(name string) (string, error) {
    // Если имя не было указано, возвращаем ошибку с сообщением.
    if name == "" {
        return name, errors.New("empty name")
    }
    // Создаем сообщение в произвольном формате.
    // message := fmt.Sprintf(randomFormat(), name)
    message := fmt.Sprint(randomFormat())
    return message, nil
}

5 В командной строке в каталоге приветствия запустите go test, чтобы выполнить тест.

На этот раз запустите go test без флага -v. Вывод будет включать результаты только тех тестов, которые не прошли проверку, что может быть полезно, когда у вас много тестов. Тест TestHelloName должен завершиться ошибкой - TestHelloEmpty все еще проходит.

$ go test
--- FAIL: TestHelloName (0.00s)
    greetings_test.go:15: Hello("Gladys") = "Hail, %v! Well met!", <nil>, want match for `\bGladys\b`, nil
FAIL
exit status 1
FAIL    example.com/greetings   0.182s

В следующем посте вы увидите, как скомпилировать и установить код для его локального запуска.


Читайте также: