1 цикл и 1 флаг и одно сравнительно сложное условие (regexp`ом будет удобно).
Сбрасываем флаг в исходное состояние (в Go достаточно его объявить, там автоматическая инициализация переменных)
Цикл такой - читаем, пока файл не закончился
Если состояние исходное, то сравниваем строку на соответствие правилу "начало с начала строки, а конец это двоеточие" (удобен будет regexp)
Если строка такая, то переходим во второе состояние, а найденная строка будет новой веткой дерева.
Если строка не такая, то ошибка
Если состояние второе, то сравниваем на то же самое условие
Если соответствует, то возвращаемся в первое состояние
Если не соответствует, то помещаем текущую строку в текущую ветку дерева.
не хочется костылить
Это рядовая программисткая задача.
Для этого не нужно никаких библиотек (кроме штатных).
Тут нет никаких хитрых алгоритмов.