Как стать автором
Обновить

Go: Как подключить внешнюю библиотеку и исключить ненужные зависимости

Время на прочтение3 мин
Количество просмотров6.8K
Автор оригинала: Rallar


TL;DR: Кодогенератор.


Представьте, что вы разрабатываете некоторую библиотеку, которая поддерживает различные драйвера для хранения данных: Postgresql, Scylla, JSON и какие-либо другие.


У каждого из этих драйверов есть внешние зависимости от других библиотек. Postgresql — database/sql, github.com/lib/pq. Scylla — github.com/scylladb/gocql или стандартный github.com/gocql/gocql. JSON — github.com/mailru/easyjson или github.com/json-iterator/go, или encoding/json.


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


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


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


Кодогенерация


Разбейте файлы на части


Разбейте файлы вашей библиотеки на логические части, которые реализуют каждую отдельную конкретную зависимость. Пример: sql.go, cql.go, json.go.


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


Упакуйте файлы


Упакуйте файлы через pkger или любое другое решение для хранения их в бинарном файле.


Для включения файлов через pkger — в исходном коде просто нужно их использовать


    files := make([]string, 0)

    if *cql {
        files = append(files, pkger.Include("/cql.go"))
    }

    if *json {
        files = append(files, pkger.Include("/json.go"))
    }

    if *sql {
        files = append(files, pkger.Include("/sql.go"))
    }

Далее запустите


pkger -o <путь к исходнику кодогенератора>

И после этого вы получите статический исходник с упакованными файлами, который будут включены в бинарный файл.


Удобно добавить генерацию в go generate


//go:generate pkger -o <путь к исходнику кодогенератора>

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


Напишите кодогенератор


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


    for i := range files {
        _, filename := filepath.Split(files[i])

        in, err := pkger.Open(files[i])
        if err != nil {
            panic(err)
        }

        src := []byte(fmt.Sprintf(genStr, strings.Join(os.Args[1:], " ")))

        reader := bufio.NewReader(in)

        for {
            line, err := reader.ReadBytes('\n')
            if strings.HasPrefix(string(line), "package ") {
                line = []byte(fmt.Sprintf("package %s\n", *pkgName))
            }

            src = append(src, line...)

            if err == io.EOF {
                break
            }

            if err != nil {
                panic(err)
            }
        }

        if err := ioutil.WriteFile(filename, src, 0644); err != nil {
            panic(err)
        }

        in.Close()
    }

Разместите исходный код вашего кодогенератора в подпапке проекта вида “cmd/<имя вашего проекта>”. Это позволит пользователю получить бинарный файл кодогенератора с тем же названием, что и название вашей библиотеки.


Использование


Пользователь устанавливает кодогенератор


go get github.com/<ваш профиль>/<ваша библиотека>/<путь к кодогенератору>

И затем запускает кодогенератор в своём проекте


<имя бинарного файла вашего кодогенератора> -sql

Когда нужно обновить вашу библиотеку — пользователь обновляет кодогенератор


go get -u github.com/<ваш профиль>/<ваша библиотека>/<путь к кодогенератору>

И затем запускает генерацию заново.


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

Теги:
Хабы:
Всего голосов 7: ↑4 и ↓3+5
Комментарии9

Публикации

Истории

Работа

Go разработчик
117 вакансий

Ближайшие события

7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань