UPD Мда, с тех пор как я в нём копался, на T4 сделали отличную документацию. Вроде все вопросы, кроме "что ставить из расширений?" отпали.
Но если есть примечания/замечания, то велкам!
Предыдущий вариант:
Подскажите, в какую сторону копать, чтоб правильно сделать следующее:
1. Есть файл \src\Assertions\Code.cs.
2. Надо рядышком положить DebugCode.tt, который будет копировать содержимое Code.cs, добавлять к имени класса префикс Debug и заменять
[DebuggerHidden]
на
[Conditional(DebugCode.DebugCondition), DebuggerHidden]
3. С code model извращаться не надо, достаточно простой дубовой замены регексами. То, что не должно попасть в DebugCode вытащу в partial-класс.
4. Очень желательно, чтобы шаблон можно было использовать в нескольких местах (T4 вроде бы умеет include?)
Чтобы если в будущем появился другой класс ассертов, можно было сослаться на тот же шаблон, а не копипастить и не поддерживать правки в обоих копиях.
Сам что-то похожее уже делал, но результат получился абсолютно неподдерживаемый. Да и T4 с тех пор основательно подзабыл.
Собственно что интересует:
1. Что из инструментов/расширений студии нужно ставить?
2. Ссылки на статьи/похожие примеры.
S>>UPD Мда, с тех пор как я в нём копался, на T4 сделали отличную документацию. Вроде все вопросы, кроме "что ставить из расширений?" отпали.
AVK>Из расширений ничего вроде как ставить не нужно.
Редактор — их несколько было. Не хочется перебирать)
Раньше надо было ставить что-то из инструментов чтоб автоматом запускался t4 при правке зависимого файла. Вот этот по-моему.
+ Надо было прописывать автозапуск t4 при сборке, чтоб оно и на билд-сервере работало.
Или с этим можно не заморачиваться и сделатьвсё вручную: "поправил файл, ручками запустил, закоммитил, забыл — сам себе буратин"?
Здравствуйте, Sinix, Вы писали:
AVK>>Из расширений ничего вроде как ставить не нужно. S>Редактор — их несколько было. Не хочется перебирать)
Никаким ни разу не пользовался.
S>+ Надо было прописывать автозапуск t4 при сборке, чтоб оно и на билд-сервере работало.
У нас сейчас генеренный файл коммитится в реп.
S>Или с этим можно не заморачиваться и сделатьвсё вручную: "поправил файл, ручками запустил, закоммитил, забыл — сам себе буратин"?
Зависит от сложности. С простенькими скриптами, имхо, проще не заморачиваться.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, AndrewVK, Вы писали:
AVK>Зависит от сложности. С простенькими скриптами, имхо, проще не заморачиваться.
Понял, обвеску инструментами будем добавлять если понадобится.
Скрипт хочу как можно проще сделать. Вариант с сложным в своё время пробовал, не понравилось.
S>1. Что из инструментов/расширений студии нужно ставить?
Для решарпера в его собственном Resharper Extensions можно найти t4tea. Имхо лучший (перебрал много), но при каких-то условиях тупит и всё красит красным. Если не тупит — то работают многие полезные решарперовские фичи.
Здравствуйте, Sinix, Вы писали:
S>UPD Мда, с тех пор как я в нём копался, на T4 сделали отличную документацию. Вроде все вопросы, кроме "что ставить из расширений?" отпали.
Если есть решарпер, то однозначно его плагин. Если нет то из всего остального глючного по выбору.
S>1. Есть файл \src\Assertions\Code.cs.
Посмотрел на этот класс, его тоже можно легко сгенерировать
S>2. Надо рядышком положить DebugCode.tt, который будет копировать содержимое Code.cs, добавлять к имени класса префикс Debug и заменять
Считать файл с использованием Host.ResolvePath. Сделать необходимые замены. Сохранить с помощью WriteLine. Всё.
S>4. Очень желательно, чтобы шаблон можно было использовать в нескольких местах (T4 вроде бы умеет include?)
Без проблем. Пишешь всю трансформацию ввиде метода вот в таких скобках <#+ ... #>, подключаешь через include.
S>Чтобы если в будущем появился другой класс ассертов, можно было сослаться на тот же шаблон, а не копипастить и не поддерживать правки в обоих копиях.
Можно не только асертов. Если туда передавать имя файла и список трансформаций, то будет применимо для чего угодно.
S>Сам что-то похожее уже делал, но результат получился абсолютно неподдерживаемый. Да и T4 с тех пор основательно подзабыл.
Чтобы больше не подзабывать проще один раз заглянуть внутрь. T4 — это простейший генератор, вся ценность которого состоит в том, что он входит в студию из коробки. А внутри у него вот что.
class MyClass
{
int _v11 = 4;
int _v21 = 3 + 1;
int _v31 = 4;
int _v41 = 3 + 1;
int _v12 = 5;
int _v22 = 3 + 2;
int _v32 = 5;
int _v42 = 3 + 2;
int _v13 = 6;
int _v23 = 3 + 3;
int _v33 = 6;
int _v43 = 3 + 3;
}
Теперь идём в C:\Users\{Account}\AppData\Local\Temp\ и находим самый свежий .cs файл.
— Имеем один сгенерированный класс GeneratedTextTransformation, наследованный от Microsoft.VisualStudio.TextTemplating.TextTransformation.
— Имеем один виртуальный метод TransformText.
— Всё, что находится внутри <# ... #> в нашем шаблоне попадает внутрь TransformText.
— Всё, что находится внутри <#+ ... #> включается в класс GeneratedTextTransformation в виде мемберов, включая объявленные классы.
— Генерируемый код — это всё, что вне <#(+) #> или внутри <#= #> как в старом ASP.NET.
— <#= #> — это по сути вызов метода Write базового класса TextTransformation.
— Методы Write, WriteLine можно вызывать напрямую в ассортименте.
— Их вызов, фактически заполняет StringBuilder, доступ к которому осуществляется напрямую через свойство GenerationEnvironment.
— Свойством GenerationEnvironment можно манипулировать напрямую как вздумается, как показано выше в примере.
В общем, тупая генерилка. Вся мощь инструмента зависит исключительно от ваших рук и фантазии.
Ну и про возможности partial классов тоже не забываем.
Здравствуйте, Sinix, Вы писали:
S>Чтобы если в будущем появился другой класс ассертов, можно было сослаться на тот же шаблон, а не копипастить и не поддерживать правки в обоих копиях.
Тогда может лучше заменить
<#@ include file="..\..\..\T4.Reusable\DebugCodeGenerator.include.tt"#>
на
<#@ include file="$(SolutionDir)\T4.Reusable\DebugCodeGenerator.include.tt"#>
Здравствуйте, _Raz_, Вы писали:
_R_>Тогда может лучше заменить
А оно будет работать, если хост от MsBuild будет?
лет 7 назад не работало, но это когда ещё было
_R_>1. Перепутаны местами paramName и message _R_>2. У T4 шаблонов есть свои параметры. Не будет ли путаницы с ними при таком типе исключения
Здравствуйте, Sinix, Вы писали:
AVK>>Зависит от сложности. С простенькими скриптами, имхо, проще не заморачиваться. S>Скинул, посмотри плиз
У меня он вообще не запускается:
Error Compiling transformation: Type expected T4.Reusable s:\Work\CodeJam\T4.Reusable\DebugCodeGenerator.include.tt 1
Error Compiling transformation: Invalid token 'this' in class, struct, or interface member declaration T4.Reusable s:\Work\CodeJam\T4.Reusable\DebugCodeGenerator.include.tt 1
Error Compiling transformation: Method must have a return type T4.Reusable s:\Work\CodeJam\T4.Reusable\DebugCodeGenerator.include.tt 1
Ну и в сгенеренном коде неплохо бы using static DebugCode; добавить.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, AndrewVK, Вы писали:
AVK>У меня он вообще не запускается:
Вот это косяк
Завтра на свежую голову буду смотреть.
AVK>Ну и в сгенеренном коде неплохо бы using static DebugCode; добавить
Ок.
Здравствуйте, AndrewVK, Вы писали:
AVK>Видимо это как то связано с настройками гита на предмет autocrlf — Т4 как то по разному относится к Unix и Windows LF.
Эва как. А это можно в gitconfig (который включён в репо, не в локальном) как-то прописать?
S>>Эва как. А это можно в gitconfig (который включён в репо, не в локальном) как-то прописать? AVK>Можно наверное. А что включать? Принудительно Windows или просто "не трогать"?
А любой, главное чтоб у всех одинаково было.
Лично я за Windows после одного эпического фейла с уходом в продакшн собранного на linux-сервере кода. С \n в строковых константах.
* разумеется, главный косяк тут был в кривых руках, но осадок остался
Здравствуйте, IT, Вы писали:
IT>По идее MSBuild вообще не должен ничего генерировать, т.к. сгенерированый файл уже есть в проекте.
По уму все шаблоны надо при сборке запускать, чтобы не было "забыл обновить".
Здравствуйте, Sinix, Вы писали:
IT>>По идее MSBuild вообще не должен ничего генерировать, т.к. сгенерированый файл уже есть в проекте. S>По уму все шаблоны надо при сборке запускать, чтобы не было "забыл обновить".
По уму не надо. Представь, что твой шаблон, например, ходит в БД за какими-нибудь метаданными, а у билд сервера доступа к этой БД нет.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>По уму не надо. Представь, что твой шаблон, например, ходит в БД за какими-нибудь метаданными, а у билд сервера доступа к этой БД нет.
Если мы про теорию, то такие редкие исключения надо в проект с condition включать, чтоб сборка на сервере их игнорила.
Здравствуйте, IT, Вы писали:
AVK>>Можно наверное. А что включать? Принудительно Windows или просто "не трогать"? IT>Лучше всего "не трогать".
Оно вот как раз было не трогать. А у кого то, видать, в локальных конфигах было трогать. В том числе вроде бы и у тебя. В результате у меня периодически студия начинала орать на не те концы строк. Так что лучше уж для определенных расширений пусть оно принудительно перетаптывает, причем у всех.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, Sinix, Вы писали:
IT>>По уму не надо. Представь, что твой шаблон, например, ходит в БД за какими-нибудь метаданными, а у билд сервера доступа к этой БД нет. S>Если мы про теорию, то такие редкие исключения надо в проект с condition включать, чтоб сборка на сервере их игнорила.
У меня такие редкие исключения в каждом проекте на работе. В общем, нет смысла париться на эту тему. MSBuild всё равно не запускает перегенерацию шаблонов. И не надо.
Если нам не помогут, то мы тоже никого не пощадим.
Подстветка и кой-какой интеллисенс (в коде шаблона) есть, а всё остальное, например интеллисенс в "генерируемом коде" за отдельную плату. Но бесплатного для хороший жизни более чем.
Здравствуйте, IT, Вы писали:
IT>Посмотрел. Не то что бы там косяки, я бы вообще всё переделал. Само по себе решение уж слишком одноразовое. Переделал на более менее переиспользуемое.
Всё как бы замечательно, код красивый, только поведение теперь поломано
0. Новый вариант неподдерживаемый. Вот что будет с вероятностью 100%: Code.tt скопипащен в десяток мест, в том числе в сторонних пакетах и тут выясняется, что надо добавить ещё один replace.
1. Нужно хардкодить имя файла с ассертами.
2. Нет проверки на строгое соответствие имени шаблона и имени исходного файла. Не проверяется, что файлы должны лежать рядом.
3. Генератор не падает, если в исходном файле нет нужного класса.
4. Нет using static CodeJam.DebugCode.
Т.е. решение теперь тоже одноразовое, но в другом смысле: для нового класса ассертов придётся не просто копировать шаблон, а ещё и менять в нём код
Все пункты (1-4) должны быть в .ttinclude, чтоб не копипастить их при необходимости поправить.
Здравствуйте, IT, Вы писали:
IT>У меня такие редкие исключения в каждом проекте на работе. В общем, нет смысла париться на эту тему. MSBuild всё равно не запускает перегенерацию шаблонов. И не надо.
Надо-надо. Как только шаблонов больше, чем пара и в проект допускают джуниора — так обязательно даже. Сколько у нас из-за этого "да не парься, найдём если что кто забыл запустить" косяков было — пальцев не хватит.
IT>MSBuild всё равно не запускает перегенерацию шаблонов. И не надо. https://www.nuget.org/packages/Clarius.TransformOnBuild/
Там только targets-файл. Подробности — тынц.
С appveyor вроде бы пашет.
Здравствуйте, xy012111, Вы писали:
X>tangible T4 Editor 2.3.0 plus modeling tools for VS 2015 Моделинг тулз в инсталяторе можно отключить, менюшку свою вроде добавляет но так ни разу не понадобилось.
Угу, вот он и стоит в итоге.
Здравствуйте, Sinix, Вы писали:
S>Т.е. решение теперь тоже одноразовое, но в другом смысле: для нового класса ассертов придётся не просто копировать шаблон, а ещё и менять в нём код
Похоже мы друг друга не поняли. Я решал такую задачу. Взять произвольный файл и произвести с ним заданные трансформации. Твоя задача как я понял другая. Каждой бабе по бутылке водки Каждому файлу по его Debug версии. Исправляюсь.
Кстати, про using static CodeJam.DebugCode не понял. Оно там всё равно нигде не используется.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, AndrewVK, Вы писали:
AVK>В результате у меня периодически студия начинала орать на не те концы строк. Так что лучше уж для определенных расширений пусть оно принудительно перетаптывает, причем у всех.
Может кто клонирует заново репозиторий? Гит в этом случае обновит все файлы и исправит концы строк, а потом закомитит изменения. А то сейчас многие файлы вместо нужных изменений содержат еще и изменения по переводу концов строк Плюс это сильно мешает слиянию и приводит к конфликтам.
Сейчас там 40 файлов такие.
ЗЫ. Можно просто удадить все файлы в рабочей директории, а потом сделать git checkout .
Здравствуйте, IT, Вы писали:
IT>Похоже мы друг друга не поняли.
Ага, в n-й раз налезаю на всё те же грабли: коммит кода без объяснений Дальше буду issues гитхаба заводить, хотя бы чиста для истории.
UPD: Коммент к коммиту
UPD2: А можно в ReplaceInfo прикрутить bool FailIfNotFound? А то одна возможность накосячить всё-таки осталась неприкрытой
IT>Кстати, про using static CodeJam.DebugCode не понял. Оно там всё равно нигде не используется.
AndrewVK выше предложил.
Чтоб в других классах отладочных ассертов писать [Conditional(DebugCondition), DebuggerHidden, MethodImpl(PlatformDependent.AggressiveInlining)]
а не [Conditional(DebugCode.DebugCondition), DebuggerHidden, MethodImpl(PlatformDependent.AggressiveInlining)]
Заодно сейчас в оригинальном классе для PlatformDependent тоже using static сделаю. Аж забавно, как легко можно упустить очевидные моменты
Здравствуйте, rameel, Вы писали:
R>Кстати, поправь заодно в файле DebugCodeGenerator.ttinclude бросаемое исключение с InvalidCastException на InvalidOperationException
Здравствуйте, Sinix, Вы писали:
S>UPD2: А можно в ReplaceInfo прикрутить bool FailIfNotFound? А то одна возможность накосячить всё-таки осталась неприкрытой
Можно всё.
Если нам не помогут, то мы тоже никого не пощадим.