Курсовая работа на тему: "Портирование инструментов автоматизации Visual Studio в Rider"
У нас на сайте представлено огромное количество информации, которая сможет помочь Вам в написании необходимой учебной работы.
Но если вдруг:
Вам нужна качественная учебная работа (контрольная, реферат, курсовая, дипломная, отчет по практике, перевод, эссе, РГР, ВКР, диссертация, шпоры...) с проверкой на плагиат (с высоким % оригинальности) выполненная в самые короткие сроки, с гарантией и бесплатными доработками до самой сдачи/защиты - ОБРАЩАЙТЕСЬ!
Курсовая работа на тему:
"Портирование инструментов автоматизации Visual Studio в Rider"
Porting Visual Studio automation tools to Rider
Course Work
Оглавление
Введение 4
1. Постановка задачи 6
2.1. Структура EnvDTE . . . . . . . . . . . . . . . . . . . . . . 7
2.2. Версии EnvDTE . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3. Существующие решения . . . . . . . . . . . . . . . . . . . 7
2.4. Rider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4.1. Архитектура . . . . . . . . . . . . . . . . . . . . . . 10
2.4.2. Протокол межпроцессного взаимодействия . . . . 11
2.4.3. Проектная модель . . . . . . . . . . . . . . . . . . . 11
2.4.4. Подсистемы, нуждающиеся в EnvDTE . . . . . . . 11
3. Предлагаемое решение 12
3.1. Архитектура решения . . . . . . . . . . . . . . . . . . . . . 12
3.1.1. Передача данных между процессами . . . . . . . . 12
3.1.2. Передача абстрактных синтаксических деревьев . 13
3.1.3. Делегирование в Rider . . . . . . . . . . . . . . . . 14
3.2. Интеграция в Rider . . . . . . . . . . . . . . . . . . . . . . 15
3.2.1. Редактирование кода . . . . . . . . . . . . . . . . . 15
3.2.2. Кодогенерация, компиляция, исполнение . . . . . 17
3.3. Ограничения . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Заключение 18
Введение
При разработке программного обеспечения может возникать по- требность многократно выполнять однотипные действия над кодом; ав- томатизация этого процесса может значительно увеличить производи- тельность труда программиста. Один из способов автоматизировать это
— написать программу, которая работает с деревями разбора файлов проекта.
Visual Studio — среда разработки от компании Microsoft — предо- ставляет программный интерфейс для этого. Это библиотека под назва- нием „EnvDTE“. Используя её, можно получить доступ к абстракциям, значительно упрощающим работу, например, к информации о структу- ре проекта и абстрактным синтаксическим деревьям, построенным по файлам с кодом. Важная черта этой библиотеки в том, что она исполь- зуется при создании расширений к среде разработки, но она позволяет взаимодействовать с моделью кода и подсистемами среды разработки без написания плагинов к ней. Например, в T41 существует простой способ получить доступ к объектам EnvDTE и взаимодействовать со средой разработки напрямую из пользовательского кода [12]. Благода- ря такому удобству этот механизм используется во многих2 проектах на платформе .NET.
Но у этой технологии есть важный недостаток: она не универсальна. Код из этой библиотеки может быть исполнен только во время работы Visual Studio, из-за чего эти инструменты невозможноиспользовать в окружениях, в которых эта среда разработки недоступна. В частности, при работе в Rider — среде разработки, созданной компанией JetBrains. В связи с этим разработчики проектов, использующих этот инстру- мент, оказываются привязаны к Visual Studio и не могут использовать Rider. Поэтому в компании JetBrains появилась потребность в решении
1T4 — шаблонный язык, используемый в .NET для генерации текста или кода. Он состоит из спе- цифичных директив, частей текста и кода на C#. Этот код исполняется до сборки основногопроекта. 2Согласно сервису по обмену кодом NuGet, на настоящий момент (2020 год) библиотека EnvDTE скачивается 850 раз в день и используется в таких проектах, как Roslyn, ILSpy,gitextensions. Актуальную информацию об использовании этой сборки можно найти на странице
https://www.nuget.org/packages/EnvDTE/
этой проблемы.
Возникла идея сделать альтернативный инструмент, который предоставлял бы те же абстракции работы с кодом, но не опирался бы на Visual Studio.
Rider при работе с кодом использует абстракции, схожие с абстрак- циями EnvDTE, поэтому ключевой шаг в реализации предлагаемой библиотеки — получение модели кода, идентичной модели кода Visual Studio, на основе данных из Rider.
EnvDTE используется в пользовательском коде, а в среде разра- ботки Rider пользовательский код, который может использовать дан- ную технологию, исполняется в процессе, отдельном отпроцесса среды разработки. Поэтому предлагаемая библиотека должна загружаться в пользовательский процесс и при помощи некоторых инструментов меж- процессного взаимодействия получать изRider необходимую информа- цию.
1. Постановка задачи
Цель данной работы заключается в создании библиотеки, предостав- ляющей такой же интерфейс проектной и кодовой модели, как EnvDTE, но способной работать в среде разработки Rider.
Для того, чтобы достичь поставленную цель, необходимо решить следующие задачи:
• создание библиотеки, имитирующей внешний программный ин- терфейс EnvDTE;
• создание плагина к среде разработки Rider, позволяющего полу- чать информацию, необходимую для реализации абстракций, ана- логичных абстракциям из EnvDTE;
• организация передачи данных между библиотекой, загруженной в пользовательский процесс, и средой разработки;
• интеграция созданного инструмента в подсистемы среды разра- ботки Rider, нуждающиеся в работе с EnvDTE.
2. Обзор предметной области
2.1. Структура EnvDTE
EnvDTE позволяет взаимодействовать со многими подсистемами IDE (рис. 1), например, отладчиком, процессом сборки решения, графи- ческим интерфейсом и так далее. Такое богатство обусловлено тем, что EnvDTE может быть использована для создания расширений к среде разработки.
Но в проектах, опирающихся на эту библиотеку, направленных на автоматизацию работы с кодом, эти абстракции не требуются. Для них достаточно обращаться к абстракциям проектноймодели. Они включа- ют в себя такие интерфейсы, как Solution, Project, CodeElement и так да- лее. EnvDTE также позволяет взаимодействовать и с деревьями разбо- ра файлов. Доступны такиеинтерфейсы, как CodeType, CodeNamespace, CodeFunction и так далее. Примечательно, что данная библиотека рас- крывает не только синтаксическую структуру кода, но и, частично, его семантику. Так,CodeClass позволяет получить список классов и интер- фейсов, от которых он наследуется, а CodeFunction – её тип.
2.2. Версии EnvDTE
В целях сохранения обратной совместимости разработчики исход- ной библиотеки не меняли существующие интерфесы EnvDTE, а созда- вали новые сборки. Поэтому в настоящее время одновременно суще- ствуют пять различных версий библиотеки; предлагаемая альтернати- ва должна позволять работать через любую версию интерфейсов.
2.3. Существующие решения
Потребность в использовании EnvDTE вне Visual Studioсуществует уже давно, и найдены следующие пути её решения:
• находить при помощи методов межпроцессного взаимодействия
• запускать новый экземпляр Visual Studio без пользовательского интерфейса и получать инструменты автоматизации из него [14].
Оба эти варианта, однако, не универсальны. Первый вариант подразу- мевает необходимость вручную открывать среду разработки, что может быть нежелательно. Второй вариант не оптимален с точки зрения про- изводительности: даже для небольших проектов инициализация про- цесса Visual Studio может занять некоторое время. Результаты измере- ния времени инициализации этого процесса представлены в таблице 1. И они оба не применимы в окружениях, в которых запуск Visual Studio невозможен. Например, на машинах, на которых не установлена эта IDE, и на всех операционных системах, кроме Windows. Ограниче- ния на платформу вызваны тем, что библиотека EnvDTE специфична для операционной системы Windows и не может быть использована,
например, в Visual Studio for Mac.
Наконец, можно удалить из проекта все завязки на EnvDTE и ис- пользовать другие инструменты для автоматизации работы с кодом. Это можно сделать, например, на основе инструмента Scripty [5]. Но для крупных проектов эта работа может оказаться трудозатратной и чреватой ошибками, поэтому этот вариант тоже применим не всегда.
Таблица 1: Результаты измерения времени инициализации Visual Studio при помощи методов межпроцессного взаимодействия [14]. E
— математическое ожидание. σ — стандартное отклонение. Решение, открытие которого измерялось, содержало 500 строк кода на C# и не находилось в системе контроля версий. Никакие плагины к среде разра- ботки установлены не были. Измерения проводились на персональном компьютере с процессором i7-8750H CPU 2.20GHz (Coffee Lake) при по- мощи инструмента BenchmarkDotNet [1].
Рис. 2: Архитектура среды разработки Rider [3].
2.4. Rider
2.4.1. Архитектура
Rider [10] — кроссплатформенная среда разработки для .NET от компании JetBrains. Она состоит из двух основных процессов опера- ционной системы: фронтенда и бэкенда. Данная схема изображена на рис. 2.
Фронтенд — видимая часть, пользовательский интерфейс — создан на основе платформы IntelliJ, благодаря чему внешний вид среды раз- работки имеет много общего с внешним видом многих других продук- тов компании JetBrains. Эта часть исполняется на виртуальной машине Java.
Бэкенд — процесс без пользовательского интерфейса, в котором со- средоточена основная логика по работе с кодом — основан на другом продукте компании JetBrains — ReSharper [4]. ReSharper — плагин к среде разработки Visual Studio [9]; для использования его в качестве бэ- кенда для среды разработки Rider ReSharper был модифицирован – код этого проекта был отвязан от программных интерфейсов Visual Studio. Эта часть исполняется на виртуальной машине .NET. Поскольку эти две части используют различные виртуальные машины, они были вы- делены в отдельные процессы.
2.4.2. Протокол межпроцессного взаимодействия
Взаимодействие между двумя процессами, составляющими Rider — ключевой момент в работе среды разработки, поэтому для упрощения этой задачи существует библиотека RD [8]. Аббревиатура RD расшиф- ровывается как „Reactive Distributed“, что точно отражает её суть: она предоставляет реактивные сущности (то есть объекты, позволяющие реагировать на изменения, подписываясь на события) и способна рабо- тать в распределённых системах. Другое важное свойство этого меха- низма заключается в том, что он позволяет иметь изменяемое состоя- ние, разделяемое между процессами, и гарантировать его консистент- ность.
Этот же механизм можно использовать и для того, чтобы обеспечить
обмен информацией между процессом, в который загружена предлага- емая библиотека, и средой разработки.
2.4.3. Проектная модель
Модель проекта в Rider имеет много общего с моделью в EnvDTE. Как и Visual Studio, Rider оперирует такими понятиями, как решение, документ, тип, а так же их составляющими: проект, каретка, метод и так далее. Близость этих моделей значительно упрощает задачу данной работы.
2.4.4. Подсистемы, нуждающиеся в EnvDTE
Особенность EnvDTE в том, что её можно использовать не толь- ко при написании плагинов к Visual Studio. Например, технология T4 позволяет обращаться к EnvDTE из пользовательского кода. В среде разработки Rider уже есть подсистема, реализующая поддержку T4. Эта система корректно работает в тех случаях, когда пользовательский код не использует EnvDTE, но выдаёт сообщение об ошибке в случае использования этой технологии. Поэтому её применимость несколько ограничена.
3. Предлагаемое решение
В ходе данной работы была реализована часть публичных ин- терфейсов EnvDTE. Эта реализация была названа JetBrains.EnvDTE. Исходный код был выложен на сервис GitHub по адресу https:// github.com/kirillgla/JetBrains.EnvDTE. Данное решение поддержи- вает ключевые функции по работе с моделью проекта и абстрактными синтаксическими деревьями.
3.1. Архитектура решения
Предлагаемое решение (рис. 3) состоит из трёх основных частей:
• сборки, содержащие интерфейсы EnvDTE;
• EnvDTE.Client – сборка, содержащая реализацию этих интерфей- сов и логику по отправке запросов;
• EnvDTE.Host – сборка, содержащая логику по обработке запросов.
Сборки с интерфейсами EnvDTE и их реализациями рассчитаны на загрузку в процесс с пользовательским кодом. Сборка с логикой по обработке запросов – на загрузку в процесс бэкенда среды разработки Rider. Предлагаемое решение дублирует версии существующих библио- тек и содержит проекты с интерфейсами каждой из версий.
3.1.1. Передача данных между процессами
Существуют разные механизмы, которыми можно воспользоваться для того, чтобы передавать данные между процессом бэкенда Rider и процессом, нуждающемся в EnvDTE. Например, Google gRPC [6] и Apache Thrift [2] являются возможными вариантами. Была выбрана библиотека RD [8]. Её достаточно для того, чтобы создавать соединение между процессом бэкенда Rider ипользовательским кодом; весомым ар- гументом в её пользу является то, что этот механизм уже используется
Рис. 3: Архитектура предлагаемой библиотеки.
в Rider. Библиотека RD подразумевает использование rdgen – инстру- мента для генерации фрагментов кода – классов, которые будут общи- ми для сторон, осуществляющих обмен данными [7]. В предлагаемой библиотеке при помощи него создаются классы модели кода. Напри- мер, классы, представляющие проекты и файлы, и узлы абстрактных синтаксических деревьев.Библиотека RD загружается в пользователь- ский процесс вместе с JetBrains.EnvDTE и передаёт запросы и ответы по каналу связи, работающему на основе сокетов.
Задача передачи информации об абстрактных синтаксических де- ревьях была разделена на конвертацию конкретного синтаксического дерева в абстрактное и передачу его в другой процесс, поэтому узлы промежуточного дерева дублируют узлы абстрактного синтаксическо- го дерева, строящегося на стороне EnvDTE.
3.1.2. Передача абстрактных синтаксических деревьев
В Rider есть инфраструктура для видонезависимого анализа фай- лов. Она позволяет построить конкретное синтаксическое дерево, кото- рое называется PSI – Program Structure Interface. При необходимости требуемые узлы преобразуются в промежуточное представление, ко- торое затем передается в пользовательский процесс и преобразуется в
узлы абстрактного синтаксического дерева EnvDTE.
Класс промежуточного представления узлов дерева, используемый обеими сторонами, генерируется при сборке предлагаемой библиотеки. Он хранит идентификатор типа узла и идентификатор узла. Иденти- фикатор типа позволяет процессу-получателю определить, к какому типу относится полученный узел, какой интерфейс он предоставляет, и соответственно, какой узел абстрактного синтаксического дерева необ- ходимо создать для него. Идентификатор узла используется при по- следующих обращениях к процессу Rider: при обработке запроса этот идентификатор позволяет однозначно определить, какой узел послу- жил основой для узла AST.
Наличие промежуточного представления позволяет ослабить связ-
ность кода: ни одна из сторон не имеет информации о том, какое пред- ставление дерева используется на другой стороне. Так, на стороне Rider невозможно использовать PSI при обращении кабстрактным синтакси- ческим деревьям классов из библиотек, и приходится использовать дру- гое представление данных, которое строится на основе метаданных из библиотек при помощимеханизмов, уже реализованных в Rider, и такая замена происходит прозрачно для стороны, использующей EnvDTE. Это также позволяет не загружать в пользовательский процесс сборки, содержащие определение PSI, что уменьшает риск коллизий. Другим ключевым моментом является ленивость преобразований и неотдели- мость передачи дерева от его построения. Благодаряэтому обе стороны не только никогда не строят деревья, используемые другой стороной, но и никогда не строят промежуточные деревья; передаются только отдельные узлы.
3.1.3. Делегирование в Rider
Получение информации о семантике кода тоже делается при помо- щи запроса из пользовательского процесса в процесс Rider. Каждый узел абстрактного синтаксического дерева хранит узел промежуточно- го представления, по которому он был построен. По узлу промежуточ- ного представления всегда можно однозначно определить, какой узел
PSI послужил его основой. После выбора узла PSI вся логика деле- гируется инфраструктуре среды разработки, в которой реализованы аналогичные операции. Таким образом, среда разработки выступает в роли бэкенда для пользовательского кода: все нетривиальные операции производятся в ней, а в пользовательский процесс загружается только легковесный посредник.
3.2. Интеграция в Rider
Была реализована интеграция библиотеки в уже существующую подсистему поддержки языка T4. Исходный код этой подсисте- мы с поддержкой EnvDTE выложен на сервис GitHub по адресу https://github.com/JetBrains/ForTea/tree/net202-envdte. Все сборки из JetBrains.EnvDTE сделаны частью плагина к среде разработки и могут быть загружены в её рантайм. Это сделано для того, чтобы иметьвоз- можность гарантировать, что на машине конечного пользователя эти сборки будут доступны, и код, опирающийся на них, можно будет ис- полнить.
3.2.1. Редактирование кода
При редактировании в T4-файлах распознаются типы из этих сбо- рок и присутствует ряд интеллектуальных функций редактора для сим- волов, специфичных для EnvDTE, например, автодополнение, подсвет- ка синтаксиса, показ документации и подсказки типов. (рис. 4). Это ре- ализовано при помощи стандартного для Rider механизма: метаданные из созданных в ходе данной работы сборок загружаются в процесс сре- ды разработки и разбираются при помощи инструментов, уже исполь- зующихся в среде разработки; интеллектуальные механизмы предо- ставляются на основе этих метаданных. Благодаря этому функции ре- дактора всегда соответствуют наиболее актуальной версии библиотеки.
Рис. 4: Пример инттеллектуальных функций редактора для символов EnvDTE в файле на языке T4.
3.2.2. Кодогенерация, компиляция, исполнение
Для того, чтобы исполнить пользовательский код на языке T4, сре- да разработки транслирует его в C#, затем компилирует и исполняет получившийся код. Кодогенерация была изменена так, чтобы к поль- зовательскому коду добавлялись строчки, при необходимости инициа- лизирующие все структуры, специфичные для данной реализации биб- лиотеки, и устанавливали соединение с процессом бэкенда Rider. При компиляции сгенерированного кода на C# пути до сборок интерфей- сов EnvDTE, являющихся частью плагина, добавляющего поддержку языка T4, передаютсякомпилятору в числе остальных библиотек, необ- ходимых для компиляции этого кода. При кодогенерации в код также добавляются строки, позволяющие виртуальной машине .NET найти и загрузить сборки из плагина в тот момент, когда пользовательский код впервые обратится к типам из них. При исполнении T4-файла процесс бэкенда Rider открывает порт, к которому пользовательский код мо- жет подключиться и отправить EnvDTE-специфичные запросы. Адрес этого порта затем передаётся дочернему процессу с пользовательским кодом в качестве переменной среды.
3.3. Ограничения
В предложенной реализации поддержаны основные функции, свя- занные с проектной моделью: с файлами и проектами; и основные функции, связанные с абстрактными синтаксическими деревьями. Все остальные функции в библиотеке не имеют содержательную реализа- цию и бросают исключение при вызове. Кроме того, созданная реа- лизация поддерживает только функции чтения: любая модификация абстрактного синтаксического дерева или проектной модели вызовет исключение.
Заключение
В рамках данной работы были выполнены следующие задачи:
• была создана библиотека, имитирующая внешний программный интерфейс EnvDTE; в ней были реализованы основные функции, связанные с проектной моделью, и основные функции, связанные с абстрактными синтаксическими деревьями.
• был создан плагин к среде разработки Rider, позволяющий по- лучать информацию, необходимую для реализации абстракций,аналогичных абстракциям из EnvDTE;
• была организована передача данных между библиотекой, загру- женной в пользовательский процесс, и средой разработки;
• был написан код, добавляющий поддержку EnvDTE в одну из под- систем Rider при помощи созданной библиотеки.
Список литературы
[1] Akinshin Andrey. BenchmarkDotNet // article. – 2019. – URL: https://benchmarkdotnet.org/articles/overview.html (дата об- ращения: 13.10.2019).
[2] Apache. Apache Thrift // Web page. – 2017. – URL: https:// thrift.apache.org/ (дата обращения: 27.11.2019).
[3] Balliauw Maarten. Rider front end plugin development // blog. – 2017. – URL: https://blog.jetbrains.com/dotnet/2017/02/ 07/rider-front-end-plugin-development/ (дата обращения: 28.10.2019).
[4] Ellis Matt. Project Rider — C# IDE // JetBrains .NET Tools Blog. – 2016. – URL:https://blog.jetbrains.com/dotnet/2016/01/13/ project-rider-a-csharp-ide/ (дата обращения: 28.10.2019).
[5] Glick Dave. Announcing Scripty // blog. – 2016. – URL: https:
//daveaglick.com/posts/announcing-scripty (дата обращения: 13.10.2019).
[6] Google. Google gRPC // Web page. – 2019. – URL: https://www. grpc.io (дата обращения: 27.11.2019).
[7] JetBrains. Protocol extension // ReSharper DevGuide. – 2018. – URL: https://www.jetbrains.com/help/resharper/sdk/Products/Rider.html#protocol-extension.
[8] JetBrains. RD // GitHub. – 2019. – URL: https://github.com/ JetBrains/rd (дата обращения: 27.10.2019).
[9] JetBrains. ReSharper // overview. – 2019. – URL: https://www. jetbrains.com/resharper/ (дата обращения: 28.10.2019).
[10] JetBrains. Rider // overview. – 2019. – URL: https://www. jetbrains.com/rider/ (дата обращения: 28.10.2019).
[11] Microsoft. Automation Model Overview // MSDN. – 2016. – URL: https://docs.microsoft.com/en-us/visualstudio/extensibility/internals/automation-model-overview (дата обращения: 06.10.2019).
[12] Microsoft. Getting data from Visual Studion // MSDN. – 2016. – URL: https://docs.microsoft.com/en-us/visualstudio/modeling/
design-time-code-generation-by-using-t4-text-templates? view=vs-2019#getting-data-from-visual-studio (дата обраще- ния: 23.11.2019).
[13] Osenkov Kiril. How to get DTE from Visual Studio process ID? // blog. – 2011. – URL: https:// blogs.msdn.microsoft.com/kirillosenkov/2011/08/10/
how-to-get-dte-from-visual-studio-process-id/ (дата об- ращения: 13.10.2019).
[14] Warren Genevieve. Launch Visual Studio using DTE // MSDN. – 2019. – URL: https://docs.microsoft.com/en-us/visualstudio/ extensibility/launch-visual-studio-dte (дата обращения: 13.10.2019).