From 82bb8a9e5cd938ce91b8b37ffa2e8f21953563dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D1=82=D0=B2=D0=B5=D0=B5=D0=B2=20=D0=9E=D0=BB?= =?UTF-8?q?=D0=B5=D0=B3=20=D0=98=D0=B3=D0=BE=D1=80=D0=B5=D0=B2=D0=B8=D1=87?= =?UTF-8?q?=20=28=D0=97=D0=9A-0001239=29?= Date: Mon, 13 Nov 2023 13:35:00 +0300 Subject: [PATCH 1/6] =?UTF-8?q?Resolve=20ORAIS-955=20/=20=20=D0=90=D0=BD?= =?UTF-8?q?=D0=B0=D0=BB=D0=B8=D0=B7=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=B2=20=D0=BA=D0=B0=D1=82=D0=B0=D0=BB=D0=BE=D0=B3=D0=B5=20?= =?UTF-8?q?=D1=81=20=D1=82=D0=BE=D1=87=D0=BA=D0=BE=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\321\210\320\270\320\261\320\276\320\272.os" | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\210\320\270\320\261\320\276\320\272.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\210\320\270\320\261\320\276\320\272.os" index 3cf8511..58e1512 100644 --- "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\210\320\270\320\261\320\276\320\272.os" +++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\210\320\270\320\261\320\276\320\272.os" @@ -38,7 +38,7 @@ СыроеЗамечание = РазобратьЗамечаниеВСтруктуру(Строка); - Если СтрНачинаетсяС(СыроеЗамечание.Сообщение, "[BSL LS]") Тогда + Если ДолженПропуститьСтроку(СыроеЗамечание) Тогда Строка = Чтение.ПрочитатьСтроку(); Продолжить; КонецЕсли; @@ -193,8 +193,8 @@ ЗначимаяСтрока = ЗначимаяСтрокаФайла(ПутьКФайлу); КешПрочитанныхФайлов.Вставить(ПутьКФайлу, ЗначимаяСтрока); Возврат ЗначимаяСтрока; - Иначе; - Возврат КешПрочитанныхФайлов.Получить(ПутьКФайлу) + Иначе + Возврат КешПрочитанныхФайлов.Получить(ПутьКФайлу); КонецЕсли; КонецФункции @@ -246,6 +246,17 @@ Возврат Замечание; +КонецФункции + +Функция ДолженПропуститьСтроку(СыроеЗамечание) + Пропуск = Ложь; + + Если (СтрНайти(СыроеЗамечание.Объект, "/.settings/") ИЛИ СтрНачинаетсяС(СыроеЗамечание.Сообщение, "[BSL LS]")) Тогда + Пропуск = Истина; + КонецЕсли; + + Возврат Пропуск; + КонецФункции; #КонецОбласти From 53ac9ea2bd30e7970475d249508ee77b38f7c3be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D1=82=D0=B2=D0=B5=D0=B5=D0=B2=20=D0=9E=D0=BB?= =?UTF-8?q?=D0=B5=D0=B3=20=D0=98=D0=B3=D0=BE=D1=80=D0=B5=D0=B2=D0=B8=D1=87?= =?UTF-8?q?=20=28=D0=97=D0=9A-0001239=29?= Date: Tue, 14 Nov 2023 09:21:32 +0300 Subject: [PATCH 2/6] =?UTF-8?q?=D0=9A=D0=BE=D0=BD=D0=B2=D0=B5=D0=B5=D1=80?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20EDT=5Fripper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Jenkinsfile | 2 ++ build-configuration.json | 12 ++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 Jenkinsfile create mode 100644 build-configuration.json diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..73da9d6 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,2 @@ +@Library(['jenkins-lib-core', 'jenkins-lib-oscript']) _ +opmPipeline() diff --git a/build-configuration.json b/build-configuration.json new file mode 100644 index 0000000..5dd14e4 --- /dev/null +++ b/build-configuration.json @@ -0,0 +1,12 @@ +{ + "sonarqube" : true, + "test" : false, + "coverage" : false, + "build" : true, + "publish" : { + "enable" : true, + "stableBranch" : "release/.*", + "develop" : true + } + } + From b69c4e2ef5acfb2095e0c541817055d948157072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BE=D0=B1=D1=88=D0=B8=D0=BA=D0=BE=D0=B2=20=D0=90?= =?UTF-8?q?=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9=20=D0=90=D0=BB=D0=B5=D0=BA?= =?UTF-8?q?=D1=81=D0=B0=D0=BD=D0=B4=D1=80=D0=BE=D0=B2=D0=B8=D1=87=20=28?= =?UTF-8?q?=D0=97=D0=9A-0001484=29?= Date: Mon, 18 Mar 2024 10:18:55 +0300 Subject: [PATCH 3/6] =?UTF-8?q?OTC-15354=20/=20EDT=20RIPPER.=20=D0=92?= =?UTF-8?q?=D0=B7=D0=B0=D0=B8=D0=BC=D0=BE=D0=B4=D0=B5=D0=B9=D1=81=D1=82?= =?UTF-8?q?=D0=B2=D0=B8=D0=B5=20=D1=81=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE?= =?UTF-8?q?=D0=BC=20=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=B2=20=D0=BE?= =?UTF-8?q?=D0=B1=D0=BB=D0=B0=D0=BA=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 8 +- Makefile | 39 + README.md | 99 +- src/main.os | 91 +- ...207\320\265\321\202\320\276\320\262BSL.os" | 22 +- ...21\200\320\260\320\262\320\270\320\273.os" | 1067 +++++++++++++++++ ...21\202\320\260\320\225\320\224\320\242.os" | 48 +- ...21\200\320\260\320\262\320\270\320\273.os" | 18 +- ...21\200\320\276\320\265\320\272\321\202.os" | 12 +- ...21\200\320\260\320\262\320\270\320\273.os" | 63 +- ...20\266\320\265\320\275\320\270\321\217.os" | 130 +- ...21\210\320\270\320\261\320\276\320\272.os" | 141 ++- ...21\200\320\260\321\206\320\270\320\270.os" | 214 +++- ...21\200\320\260\321\206\320\270\320\270.os" | 2 +- 14 files changed, 1817 insertions(+), 137 deletions(-) create mode 100644 Makefile create mode 100644 "src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\227\320\260\320\263\321\200\321\203\320\267\321\207\320\270\320\272\320\237\321\200\320\260\320\262\320\270\320\273.os" diff --git a/.gitignore b/.gitignore index 5b2624a..25c57a4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,10 @@ edt-validate-results-en out.json *.ospx .DS_Store -out/* \ No newline at end of file +out/* +.idea/**/* +.vscode/**/* +.rules/**/* +.results/**/* +.build/**/* +.report/**/* \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ed34ef4 --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ +# Определение переменной VERSION с помощью выполнения команды oscript -version +VERSION := $(shell oscript -version) + +# Переменная параметров сборки пакета модуля с учетом версии oscript +ifeq ($(VERSION), 1.0.19.105) + BUILD_PARAMS := build -mf ./packagedef -out . +else + BUILD_PARAMS := build -m ./packagedef -o . +endif + +# Переменная параметров установки модуля из пакета *.ospx +INSTALL_PARAMS := install -f *.ospx + +# Переменная для максимальной длины строки сообщения +MAX_LENGTH := 90 + +# Команда build +build: + @$(call print_message, "Собираем пакет модуля edt-ripper") + @$(call print_message, "Используемые параметры: $(BUILD_PARAMS)") + @opm $(BUILD_PARAMS) + @$(call print_message, "Пакет edt-ripper успешно построен!") + +# Команда install +install: + @$(call print_message, "Важно! Для корректной установки нужны права администратора") + @$(call print_message, "Устанавливаем пакет edt-ripper") + @opm $(INSTALL_PARAMS) + +# Функция, которая выводит сообщение в рамке из символов +# Аргумент: $(1) - сообщение +define print_message + $(eval MSG_TRUNCATED := $(shell echo "$(1)" )) + $(eval MSG_LEN := $(shell echo '$(MSG_TRUNCATED)' | wc -m)) + $(eval MSG_SPACES := $(shell expr "$(MAX_LENGTH)" - "$(MSG_LEN)")) + $(info ┌$(shell printf "─%.0s" $$(seq 1 $(MAX_LENGTH)))┐) + $(info │ $(MSG_TRUNCATED)$(shell printf '%-$(MSG_SPACES)s')|) + $(info └$(shell printf "─%.0s" $$(seq 1 $(MAX_LENGTH)))┘) +endef \ No newline at end of file diff --git a/README.md b/README.md index 8211ab5..0cfe1ad 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ Консольная утилита для работы с замечаниями ЕДТ и файлами правил для SQ. выполняет разбор EDT отчета анализа проекта. Формирует результат в формате bsl-ls. Мапит обнаруженные замечания с правилами (внутренний файл правил, внешний файл правил) -## Возможности +## Возможности (команды) - 1. Команда `parse` - Преобразует файл с результатом анализа проекта из ЕДТ в отчет формата BSL LS. Если замечание будет новое, для которого еще нет правила, оно будет добавлено в хранилище правил. + 1. Команда `parse` - преобразует файл с результатом анализа проекта из ЕДТ в отчет формата BSL LS. Если замечание будет новое, для которого еще нет правила, оно будет добавлено в хранилище правил. 2. Команда `publish` - удалит всю служебную информацию из хранилища правил. Итоговый файл готов к загрузке в SQ. @@ -13,7 +13,7 @@ + Версия EDT > 2021.2 -## Предварительные настройки и порядок использования +## Предварительные настройки проекта SonarQube Действия выполняются через UI SQ или через sonar.properties @@ -24,26 +24,105 @@ + Проверить что правила появились. Ввиду особенности работы SQ может потребоваться удалить и установить плагин sonar-bsl чтобыправила обновились в профиле качества. + Путь к файлу с результатом работы программы указывается в свойстве `sonar.bsl.languageserver.reportPaths` сканера SQ -## Пример использования +## Использование -+ Разобрать замечания ЕДТ для проекта *configuration* в репозитории *my_awersome_rep* с внешним файлом правил и создать отчет *out.json*. +### Ключи + +Ключ `--help` покажет справку по глобальным параметрам + +Ключ `--version` используется для вывода на экран текущей версии программы.
При использовании этого ключа программа выведет на экран информацию о текущей версии и затем завершит свою работу. + +Ключ `-v / --verbose` используется для включения режима подробного вывода. +
При использовании этого ключа программа будет выводить дополнительную информацию в процессе своей работы, чтоб может быть полезно при отладке. + +Ключ `-f / --file` позволяет указать внешний путь к файлу с правилами. По-умолчанию (если не указано) будет использоваться внутренний путь до файла с правилами, расположенный в каталоге с программой. + +Ключ `--export-rule-errors` указывает, следует ли сохранять ошибки, обнаруженные в процессе анализа (парсинга) замечаний в отдельный файл `custom-rules-errors.json`. + +Ключ `--nexus-rules-url` указывает URL-адрес до внешнего файла правил в репозитории Nexus. Если используется этот ключ, то ключ `-f / --file` - игнорируется. + +Ключ `--nexus-auth-username` указывает имя пользователя, используемое для аутентификации в Nexus. Имя пользователя обычно используется в паре с ключом `--nexus-auth-password`. + +Ключ `--nexus-auth-password` указывает пароль пользователя, используемый для аутентификации в Nexus. Аналогично ключу выше, также используется в паре с ключом `--nexus-auth-username`. + +### Переменные окружения + +Переменные окружения служат в качестве альтернативы для большинства ключей. +|Переменная окружения|Тип|Ключ| +|-|-|-| +|`EDT_RIPPER_VERBOSE`|Булево|`verbose`| +|`EDT_RIPPER_RULES_FILE`|Строка|`file`| +|`EDT_RIPPER_EXPORT_RULES_ERRORS`|Булево|`export-rule-errors`| +|`EDT_RIPPER_NEXUS_RULES_URL`|Строка|`nexus-rules-url`| +|`EDT_RIPPER_NEXUS_AUTH_USERNAME`|Строка|`nexus-auth-username`| +|`EDT_RIPPER_NEXUS_AUTH_PASSWORD`|Строка|`nexus-auth-password`| + +## Примеры использования + +### 1. Анализ замечаний (команда "parse") + +Эта команда используется в качестве "первичной" и готовит выходной файл для публикации. + +
Использование ключей + ++ Разобрать замечания ЕДТ для проекта *configuration* в репозитории *my_awersome_rep* с внешним файлом правил и создать отчет *out.json*. + +```shell +edt-ripper -f /mnt/share/custom-rules.json parse ./edt-validate-results ./my_awersome_rep/ configuration ./out.json +``` + ++ Разобрать замечания ЕДТ для проекта *configuration* в репозитории *my_awersome_rep* с внутренним файлом правил и создать отчет *out.json* + +```shell + edt-ripper parse ./edt-validate-results ./my_awersome_rep/ configuration ./out.json +``` + +
Использование переменных окружения + +```shell +export EDT_RIPPER_RULES_FILE=/mnt/share/custom-rules.json + +edt-ripper parse ./edt-validate-results ./my_awersome_rep/ configuration ./out.json +``` + +
Использование записи ошибок ```shell - edt-ripper -f /mnt/share/custom-rules.json parse ./edt-validate-results ./my_awersome_rep/ configuration ./out.json +export EDT_RIPPER_EXPORT_RULES_ERRORS="Истина" +export EDT_RIPPER_RULES_FILE=/mnt/share/custom-rules.json + +edt-ripper parse ./edt-validate-results ./my_awersome_rep/ configuration ./out.json + ``` -+ Разобрать замечания ЕДТ для проекта *configuration* в репозитории *my_awersome_rep* с внутренним файлом правил и создать отчет *out.json* +
Использование "ЗагрузчикаПравил" (взаимодействие с [Sonatype Nexus Repository](https://www.sonatype.com/products/sonatype-nexus-repository)) ```shell - edt-ripper parse ./edt-validate-results ./my_awersome_rep/ configuration ./out.json +export EDT_RIPPER_EXPORT_RULES_ERRORS="Истина" +export EDT_RIPPER_NEXUS_RULES_URL="http://localhost:8080/repository/test/edt-ripper/custom-rules.json", +export EDT_RIPPER_NEXUS_AUTH_USERNAME="adm1n", +export EDT_RIPPER_NEXUS_AUTH_PASSWORD="P@SSw0rd256", + +edt-ripper parse ./edt-validate-results ./my_awersome_rep/ configuration ./out.json + ``` -+ Разобрать замечания для проектов *configuration* и *exts* в репозитории *my_awersome_rep* с внутренним файлом правил и создать отчет *out.json* +### 2. Публикация подготовленного файла замечаний для SQ (команда "publish") + +Эта команда используется в качестве "завершающей". Готовит локально публикацию файла замечаний для SQ. + +
Использование переменных окружения ```shell - edt-ripper parse ./edt-validate-results ./my_awersome_rep/ configuration exts ./out.json +export EDT_RIPPER_NEXUS_RULES_URL="http://localhost:8080/repository/test/edt-ripper/custom-rules.json", +export EDT_RIPPER_NEXUS_AUTH_USERNAME="adm1n", +export EDT_RIPPER_NEXUS_AUTH_PASSWORD="P@SSw0rd256", + +edt-ripper "publish" "./.report/out.json" ``` +--- + ## todo + Поддержка файла исключений diff --git a/src/main.os b/src/main.os index 99f49e0..69699f3 100644 --- a/src/main.os +++ b/src/main.os @@ -1,50 +1,103 @@ #Использовать "." #Использовать cli -Перем Лог; +Перем Лог; // Переменная для хранения логов +Перем ЗагрузчикПравил; // Экземпляр класса загрузчика правил Процедура ВыполнитьПриложение() - + Приложение = Новый КонсольноеПриложение(ПараметрыПриложения.ИмяПриложения(), "Приложение для работы с файлами ошибок статических анализаторов", ЭтотОбъект); - + Приложение.Версия("version", ПараметрыПриложения.Версия()); Приложение.Опция("v verbose", Ложь, "Вывод отладочной информация в процессе выполнения") - .Флаговый(); + .Флаговый().ВОкружении("EDT_RIPPER_VERBOSE"); Приложение.Опция("f file", "", "Путь к внешнему файлу-коллектору замечаний") - .ТСтрока(); + .ТСтрока().ВОкружении("EDT_RIPPER_RULES_FILE"); + + Приложение.Опция("export-rule-errors", "", "Экспорт ошибок возникающих при проверке замечаний по указанным правилам") + .Флаговый().ВОкружении("EDT_RIPPER_EXPORT_RULES_ERRORS"); + + Приложение.Опция("nexus-rules-url", "", "URL-адрес внешнего файла-коллектора замечаний + | (если используется, то чтение файла по флагу '-f/--file' - игнорируется)") + .ТСтрока().ВОкружении("EDT_RIPPER_NEXUS_RULES_URL"); - Приложение.ДобавитьКоманду("parse", "Создание отчета", - Новый КомандаПарсерОтчетаЕДТ); + Приложение.Опция("nexus-auth-username", "", "Имя пользователя для при получении файла-коллектора замечаний") + .ТСтрока().ВОкружении("EDT_RIPPER_NEXUS_AUTH_USERNAME"); + Приложение.Опция("nexus-auth-password", "", + "Пароль пользователя для аутентификации при получении файла-коллектора замечаний") + .ТСтрока().ВОкружении("EDT_RIPPER_NEXUS_AUTH_PASSWORD"); + + Приложение.ДобавитьКоманду("parse", "Создание отчета", Новый КомандаПарсерОтчетаЕДТ); Приложение.ДобавитьКоманду("publish", "Удаление из выбранного файла правил служебных блоков, - | результирующий файл готов для загрузки в сонар", - Новый КомандаПубликацияПравил); - + | результирующий файл готов для загрузки в сонар", Новый КомандаПубликацияПравил); + Приложение.Запустить(АргументыКоманднойСтроки); КонецПроцедуры Процедура ПередВыполнениемКоманды(Знач Команда) Экспорт - - ОтладкаВключена = Команда.ЗначениеОпции("verbose"); + ОтладкаВключена = Команда.ЗначениеОпции("verbose"); ПараметрыПриложения.УстановитьРежимОтладки(ОтладкаВключена); - ВнешнийФайлОписаний = Команда.ЗначениеОпции("file"); + ЗаписыватьОшибкиПравил = Команда.ЗначениеОпции("export-rule-errors") = Истина; + ПараметрыПриложения.УстановитьРежимЗаписиОшибокПравил(ЗаписыватьОшибкиПравил); - Если ЗначениеЗаполнено(ВнешнийФайлОписаний) Тогда - Файл = Новый Файл(ВнешнийФайлОписаний); - Если НЕ (Файл.Существует() И Файл.ЭтоФайл()) Тогда - Лог.КритичнаяОшибка("Файл %1 недоступен", ВнешнийФайлОписаний); - КонецЕсли; + ПолныйАдресРесурса = Команда.ЗначениеОпции("nexus-rules-url"); + ПутьВнешнегоФайлаОписаний = Команда.ЗначениеОпции("file"); + + НеЗаданыОсновныеПараметры = + НЕ ЗначениеЗаполнено(ПолныйАдресРесурса) И НЕ ЗначениеЗаполнено(ПутьВнешнегоФайлаОписаний); + + Если НеЗаданыОсновныеПараметры Тогда + Возврат; + КонецЕсли; + + Если ЗначениеЗаполнено(ПолныйАдресРесурса) Тогда + + Логин = Команда.ЗначениеОпции("nexus-auth-username"); + Пароль = Команда.ЗначениеОпции("nexus-auth-password"); + Токен = ""; // TODO: При необходимости + + ЗагрузчикПравил = ПараметрыПриложения + .ПолучитьЗагрузчикПравил() + .Инициализировать(ПолныйАдресРесурса, Логин, Пароль, Токен) + .УстановитьЛокальныйКонтекстСохранения() + .УстановитьЛокальныйКонтекстСохраненияОшибок() + .ЗагрузитьПравилаИзКонтекстаНаУдаленныйУзелПриОтсутствии() + .ЗагрузитьОшибкиПравилИзКонтекстаНаУдаленныйУзелПриОтсутствии() + .ПереопределитьКонтекстСохранения("./.rules/custom-rules.json") + .ПереопределитьКонтекстСохраненияОшибок("./.rules/custom-rules-errors.json") + .ПолучитьПравилаСУдаленногоУзла() + .ПолучитьОшибкиПравилСУдаленногоУзла() + .ЗаписатьПравилаВФайл() + .ЗаписатьОшибкиПравилВФайл(); + + Возврат; + + КонецЕсли; + + Если Не ФайловыеОперации.ПроверитьСуществованиеФайла(ПутьВнешнегоФайлаОписаний) Тогда + ТекстОшибки = + ?(Не ЗначениеЗаполнено(ПутьВнешнегоФайлаОписаний), + "Не определен путь до файла правил", + СтрШаблон("Файл правил недоступен по указанному пути '%1'", СокрЛП(ПутьВнешнегоФайлаОписаний))); + + ВызватьИсключение ТекстОшибки; КонецЕсли; - ПараметрыПриложения.УстановитьКонтекстСохранения(ВнешнийФайлОписаний); + ПараметрыПриложения.УстановитьКонтекстСохранения(ПутьВнешнегоФайлаОписаний); + ПараметрыПриложения.УстановитьКонтекстСохраненияОшибок(""); + +КонецПроцедуры +Процедура ВыполнитьКоманду(Знач КомандаПриложения) Экспорт + КомандаПриложения.ВывестиСправку(); КонецПроцедуры Лог = ПараметрыПриложения.Лог(); diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\236\321\202\321\207\320\265\321\202\320\276\320\262BSL.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\236\321\202\321\207\320\265\321\202\320\276\320\262BSL.os" index a624388..2d530c3 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\236\321\202\321\207\320\265\321\202\320\276\320\262BSL.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\236\321\202\321\207\320\265\321\202\320\276\320\262BSL.os" @@ -50,15 +50,17 @@ Путь = ОбъединитьПути(ТекущийКаталог(), "edt-bsl-report.json"); КонецЕсли; + АбсолютныйПуть = ФС.ПолныйПуть(Путь); + ЗаписьJSON = Новый ЗаписьJSON; - ЗаписьJSON.ОткрытьФайл(Путь, "UTF-8", , Новый ПараметрыЗаписиJSON(, Символы.Таб)); + ЗаписьJSON.ОткрытьФайл(АбсолютныйПуть, "UTF-8", , Новый ПараметрыЗаписиJSON(, Символы.Таб)); ИзменитьСтруктуруОтчета(); ЗаписатьJSON(ЗаписьJSON, Отчет); ЗаписьJSON.Закрыть(); - Лог.Информация("Записан файл %1", Путь); + Лог.Информация("Записан файл отчета %1", АбсолютныйПуть); КонецПроцедуры @@ -87,18 +89,6 @@ КонецФункции -Функция ПрочитатьОбъект(ПутьКФайлу, ВСоответствие = Истина) - - ЧтениеJSON = Новый ЧтениеJSON; - ЧтениеJSON.ОткрытьФайл(ПутьКФайлу, "UTF-8"); - - Объект = ПрочитатьJSON(ЧтениеJSON, ВСоответствие); - ЧтениеJSON.Закрыть(); - - Возврат Объект; - -КонецФункции - Функция ШаблонОтчет() Возврат ОбъединитьПути(ТекущийСценарий().Каталог, "..", Ресурсы(), "report.json"); @@ -119,13 +109,13 @@ Функция Замечание() - Возврат ПрочитатьОбъект(ШаблонЗамечания(), Ложь); + Возврат ФайловыеОперации.ПрочитатьОбъект(ШаблонЗамечания(), Ложь); КонецФункции Процедура ПриСозданииОбъекта() - Отчет = ПрочитатьОбъект(ШаблонОтчет()); + Отчет = ФайловыеОперации.ПрочитатьОбъект(ШаблонОтчет()); Отчет["date"] = Формат(ТекущаяУниверсальнаяДата(), "ДФ='yyyy-MM-dd HH:mm:ss'"); diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\227\320\260\320\263\321\200\321\203\320\267\321\207\320\270\320\272\320\237\321\200\320\260\320\262\320\270\320\273.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\227\320\260\320\263\321\200\321\203\320\267\321\207\320\270\320\272\320\237\321\200\320\260\320\262\320\270\320\273.os" new file mode 100644 index 0000000..63c68a5 --- /dev/null +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\227\320\260\320\263\321\200\321\203\320\267\321\207\320\270\320\272\320\237\321\200\320\260\320\262\320\270\320\273.os" @@ -0,0 +1,1067 @@ + +#Использовать logos + +#Область ОписаниеПеременных + +Перем Лог; // Переменная для хранения логов +Перем СтруктураURI; // Структура URI + +Перем ПравилаJSON; // JSON-объект правил (инициируется 1 раз при получении правил с удаленного узла) +Перем ОшибкиJSON; // JSON-объект ошибок правил + +#КонецОбласти + + +#Область ПрограммныйИнтерфейс + +// Возвращает инициализированный объект загрузчика правил +// +// Параметры: +// ПолныйАдресРесурса - Строка - Полный URL адрес +// Логин - Строка - (не обязательный) Basic Auth: имя учетной записи +// Пароль - Строка - (не обязательный) Basic Auth: пароль учетной записи +// Токен - Строка - (не обязательный) Baerer Token: токен +// +// Возвращаемое значение: +// ЗагрузчикПравил - инициализированный объект загрузчика правил +// +Функция Инициализировать(ПолныйАдресРесурса, Логин, Пароль, Токен) Экспорт + ИнициализироватьСтруктуруURI(); + ЗаполнитьБазовыеПараметрыСтруктурыURI(ПолныйАдресРесурса); + ЗаполнитьПараметрыBasicAuth(Логин, Пароль); + ЗаполнитьПараметрыBaererToken(Токен); + + Возврат ЭтотОбъект; +КонецФункции + +// Читает файл с удаленного узла +// * Выполняет REST-запрос (GET) +// +// Параметры: +// НовоеИмяФайла - Строка - если заполнено, то имя читаемого файла будет изменено +// НовыйПутьНаСервере - Строка - если заполнено, будет использоваться указанный путь для получения читаемого файла +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ПрочитатьФайлСУдаленногоУзла(НовоеИмяФайла = "", НовыйПутьНаСервере = "") Экспорт + + ПроверитьНаличиеСтруктурыURI(); + + ИмяФайла = НовоеИмяФайла; + Если Не ЗначениеЗаполнено(ИмяФайла) Тогда + ИмяФайла = ФайловыеОперации.ПолучитьИмяФайла(СтруктураURI.ИмяФайлаНаСервере); + КонецЕсли; + + НоваяСтруктураURI = СоздатьКопиюСтруктурыURI(СтруктураURI, НовыйПутьНаСервере, ИмяФайла); + + ПолныйАдрес = НоваяСтруктураURI.ПолныйАдресРесурса; + ПутьНаСервере = НоваяСтруктураURI.ПутьНаСервере; + + Лог.Отладка("Чтение файла '%1' с удаленного узла %2", ИмяФайла, ПолныйАдрес); + + ИмяМетода = "GET"; + РезультатЗапроса = Неопределено; + + HTTPЗаголовки = ПодготовитьHTTPЗаголовоки(); + HTTPЗапрос = ПодготовитьHTTPЗапрос(ИмяМетода, HTTPЗаголовки, "", ПутьНаСервере); + РезультатЗапроса = ВыполнитьHTTPЗапрос(HTTPЗапрос, ИмяМетода); + + КодСостояния = РезультатЗапроса.КодСостояния; + + Если ЭтоДопустимыйКодСостоянияРезультата(КодСостояния) Тогда + Лог.Отладка("Файл '%1' успешно прочитан с удаленного узла %2 [%3]", ИмяФайла, ПолныйАдрес, КодСостояния); + Иначе + Лог.Отладка("Не удалось прочитать файл '%1' с удаленного узла %2 [%3]", ИмяФайла, ПолныйАдрес, КодСостояния); + КонецЕсли; + + ПроанализироватьКодСостоянияРезультата(РезультатЗапроса); + + Возврат РезультатЗапроса; + +КонецФункции + +// Получает файл правил с удаленного узла +// * Используется в качестве "обертки" над функцией "ПрочитатьФайлСУдаленногоУзла" с определенными параметрами +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ПолучитьПравилаСУдаленногоУзла() Экспорт + РезультатЗапроса = ПрочитатьФайлСУдаленногоУзла(); + Если ЭтоДопустимыйКодСостоянияРезультата(РезультатЗапроса.КодСостояния) Тогда + ИнициализироватьОбъектПравилИзТелаРезультатаЗапроса(РезультатЗапроса); + КонецЕсли; + Возврат ЭтотОбъект; +КонецФункции + +// Получает файл ошибок правил с удаленного узла +// * Используется в качестве "обертки" над функцией "ПрочитатьФайлСУдаленногоУзла" с определенными параметрами +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ПолучитьОшибкиПравилСУдаленногоУзла() Экспорт + КонтекстОшибок = ПараметрыПриложения.ПолучитьКонтекстОшибок(); + ИмяФайла = ФайловыеОперации.ПолучитьИмяФайла(КонтекстОшибок); + РезультатЗапроса = ПрочитатьФайлСУдаленногоУзла(ИмяФайла); + Если ЭтоДопустимыйКодСостоянияРезультата(РезультатЗапроса.КодСостояния) Тогда + ИнициализироватьОбъектОшибокПравилИзТелаРезультатаЗапроса(РезультатЗапроса); + КонецЕсли; + Возврат ЭтотОбъект; +КонецФункции + +// Отправляет файл на удаленный узел +// * Выполняет REST-запрос (PUT/POST) +// * В основном применяется для отправки правил/ошибок правил в Nexus +// +// Параметры: +// ПутьФайла - Строка - (обязательный) путь до файла, содержимое которого нужно отправить на удаленный узел +// УникальноеИмяФайла - Булево - Если Истина, то на удаленном узле будет создан файл с уникальный именем +// НовоеИмяФайла - Строка - новое имя файла +// НовыйПутьНаСервере - Строка - Специфический путь на сервере +// +// Возвращаемое значение: +// HTTPРезультат - результат выполнения запроса +// +Функция ОтправитьФайлНаУдаленныйУзел( + ПутьФайла, УникальноеИмяФайла = Ложь, НовоеИмяФайла = "", НовыйПутьНаСервере = "") Экспорт + + ПроверитьНаличиеСтруктурыURI(); + + ИмяФайла = НовоеИмяФайла; + Если Не ЗначениеЗаполнено(ИмяФайла) Тогда + ИмяФайла = ФайловыеОперации.ПолучитьИмяФайла(ПутьФайла); + КонецЕсли; + + НоваяСтруктураURI = СоздатьКопиюСтруктурыURI(СтруктураURI, НовыйПутьНаСервере, ИмяФайла); + + ТелоЗапроса = ФайловыеОперации.ПрочитатьФайл(ПутьФайла); + + Если НЕ ЗначениеЗаполнено(ТелоЗапроса) Тогда + ВызватьИсключение СтрШаблон("Невозможно выполнить отправку пустого содержимого файла '%1'", ПутьФайла); + КонецЕсли; + + ИмяМетода = "PUT"; + РезультатЗапроса = Неопределено; + + Если УникальноеИмяФайла Тогда + ИмяМетода = "POST"; + УстановитьУникальноеИмяФайлаПравил(); + КонецЕсли; + + ПутьНаСервере = НоваяСтруктураURI.ПутьНаСервере; + Если ЗначениеЗаполнено(НовыйПутьНаСервере) Тогда + ПутьНаСервере = НовыйПутьНаСервере; + КонецЕсли; + + ПолныйАдрес = НоваяСтруктураURI.ПолныйАдресРесурса; + + HTTPЗаголовки = ПодготовитьHTTPЗаголовоки(); + HTTPЗапрос = ПодготовитьHTTPЗапрос(ИмяМетода, HTTPЗаголовки, ТелоЗапроса, ПутьНаСервере); + + РезультатЗапроса = ВыполнитьHTTPЗапрос(HTTPЗапрос, ИмяМетода); + КодСостояния = РезультатЗапроса.КодСостояния; + + ПроанализироватьКодСостоянияРезультата(РезультатЗапроса); + + Если ЭтоДопустимыйКодСостоянияРезультата(КодСостояния) Тогда + Лог.Информация("Файл '%1' отправлен на удаленный узел %2 [%3]", ИмяФайла, ПолныйАдрес, КодСостояния); + Иначе + Лог.Отладка("Не удалось отправить файл '%1' с удаленного узла %2 [%3]", ИмяФайла, ПолныйАдрес, КодСостояния); + КонецЕсли; + + + Возврат РезультатЗапроса; + +КонецФункции + +// Отправляет файл правил на удаленный узел +// * Используется в качестве "обертки" над функцией "ОтправитьФайлНаУдаленныйУзел" с определенными параметрами +// +// Параметры: +// ОтправитьПриНаличииОтличий - Булево - Если "Истина", +// отправка будет выполнена только при наличии отличий правил контекста и правил полученных с удаленного узла +// (по-умолчанию: Ложь) +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ОтправитьПравилаНаУдаленныйУзел(ОтправитьПриНаличииОтличий = Ложь) Экспорт + + ПроверитьНаличиеСтруктурыURI(); + + Если ОтправитьПриНаличииОтличий Тогда + + Если НайтиОтличияПравилСУдаленногоУзлаИПравилКонтекста() Тогда + Лог.Информация("Требуется обновление правил на удаленном узле"); + ОтправитьПравилаНаУдаленныйУзел(); + Иначе + Лог.Информация("Обновление файла правил на удаленном узле не требуется"); + КонецЕсли; + + Возврат ЭтотОбъект; + + КонецЕсли; + + Контекст = ПараметрыПриложения.ПолучитьКонтекст(); + + // Обработка результата запроса не требуется + РезультатЗапроса = ОтправитьФайлНаУдаленныйУзел(Контекст); + + Возврат ЭтотОбъект; + +КонецФункции + +// Отправляет файл ошибок правил на удаленный узел +// * Используется в качестве "обертки" над функцией "ОтправитьФайлНаУдаленныйУзел" с определенными параметрами +// +// Параметры: +// ОтправитьПриНаличииОтличий - Булево - Если "Истина", +// отправка будет выполнена только при наличии отличий правил контекста и правил полученных с удаленного узла +// (по-умолчанию: Ложь) +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ОтправитьОшибкиПравилНаУдаленныйУзел(ОтправитьПриНаличииОтличий = Ложь) Экспорт + + Если Не ПараметрыПриложения.ПолучитьРежимЗаписиОшибокПравил() Тогда + Возврат ЭтотОбъект; + КонецЕсли; + + ПроверитьНаличиеСтруктурыURI(); + + Если ОтправитьПриНаличииОтличий Тогда + + Если НайтиОтличияОшибокПравилСУдаленногоУзлаИОшибокПравилКонтекста() Тогда + Лог.Информация("Требуется обновление файла ошибок правил на удаленном узле"); + ОтправитьОшибкиПравилНаУдаленныйУзел(); + Иначе + Лог.Информация("Обновление файла ошибок правил на удаленном узле не требуется"); + КонецЕсли; + + Возврат ЭтотОбъект; + + КонецЕсли; + + КонтекстОшибок = ПараметрыПриложения.ПолучитьКонтекстОшибок(); + + // Обработка результата запроса не требуется + РезультатЗапроса = ОтправитьФайлНаУдаленныйУзел(КонтекстОшибок, Ложь); + + Возврат ЭтотОбъект; + +КонецФункции + +#КонецОбласти + + +#Область СлужебныйПрограммныйИнтерфейс + +// Устанавливает локальный контекст сохранения правил +// +// Параметры: +// ПроверитьКонтекст - Булево - Если Истина - будет выполнена проверка существования контекста +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция УстановитьЛокальныйКонтекстСохранения(ПроверитьКонтекст = Истина) Экспорт + ПараметрыПриложения.УстановитьКонтекстСохранения(""); + + Если ПроверитьКонтекст Тогда + ПроверитьНаличиеКонтекста(ПараметрыПриложения.ПолучитьКонтекст()); + КонецЕсли; + + Возврат ЭтотОбъект; +КонецФункции + +// Устанавливает локальный контекст сохранения ошибок +// +// Параметры: +// ПроверитьКонтекстОшибок - Булево - Если Истина - будет выполнена проверка существования контекста +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция УстановитьЛокальныйКонтекстСохраненияОшибок(ПроверитьКонтекстОшибок = Истина) Экспорт + + ПараметрыПриложения.УстановитьКонтекстСохраненияОшибок(""); + + Если ПроверитьКонтекстОшибок Тогда + КонтекстОшибок = ПараметрыПриложения.ПолучитьКонтекстОшибок(); + КорректныйПутьКонтекстаОшибок = ФайловыеОперации.ПолучитьКорректныйПутьФайла(КонтекстОшибок); + Если Не ФайловыеОперации.ПроверитьСуществованиеФайла(КорректныйПутьКонтекстаОшибок) Тогда + ФайловыеОперации.ЗаписатьОбъект(КорректныйПутьКонтекстаОшибок, Новый Массив); + Лог.Информация("Создан пустой файл контекста ошибок: %1", КорректныйПутьКонтекстаОшибок); + КонецЕсли; + ПроверитьНаличиеКонтекста(ПараметрыПриложения.ПолучитьКонтекстОшибок()); + КонецЕсли; + + Возврат ЭтотОбъект; +КонецФункции + +// Проверяет наличие (файла) контекста +// * В случае отсутствия файла по пути контекста - выполняется вызов исключения. +// +// Параметры: +// Контекст - Строка - путь до файла контекста +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ПроверитьНаличиеКонтекста(Контекст) Экспорт + КорректныйПутьФайлаКонтекста = ФайловыеОперации.ПолучитьКорректныйПутьФайла(Контекст); + Если Не ФайловыеОперации.ПроверитьСуществованиеФайла(КорректныйПутьФайлаКонтекста) Тогда + Лог.Ошибка("Отсутствует файл контекста сохранения %1", КорректныйПутьФайлаКонтекста); + ВызватьИсключение("Ошибка получения файла контекста"); + КонецЕсли; + Возврат ЭтотОбъект; +КонецФункции + +// Выполняет отправку файла правил на удаленный узел +// по текущему контексту,, при условии, что на удаленном узле такого файла нет. +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ЗагрузитьПравилаИзКонтекстаНаУдаленныйУзелПриОтсутствии() Экспорт + Лог.Отладка("Проверка наличия файла правил на удаленном узле"); + РезультатЗапроса = ПрочитатьФайлСУдаленногоУзла(); + Если РезультатЗапроса.КодСостояния <> 200 Тогда + Лог.Отладка("Необходимо отправить файл правил на удаленный узел"); + ОтправитьПравилаНаУдаленныйУзел(); + КонецЕсли; + Возврат ЭтотОбъект; +КонецФункции + +// Выполняет отправку файла ошибок правил на удаленный узел +// по текущему контексту ошибок, при условии, что на удаленном узле такого файла нет. +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ЗагрузитьОшибкиПравилИзКонтекстаНаУдаленныйУзелПриОтсутствии() Экспорт + Лог.Отладка("Проверка наличия файла ошибок правил на удаленном узле"); + КонтекстОшибок = ПараметрыПриложения.ПолучитьКонтекстОшибок(); + ИмяФайла = ФайловыеОперации.ПолучитьИмяФайла(КонтекстОшибок); + РезультатЗапросаОшибок = ПрочитатьФайлСУдаленногоУзла(ИмяФайла); + Если РезультатЗапросаОшибок.КодСостояния <> 200 Тогда + Лог.Отладка("Необходимо отправить файл ошибок правил на удаленный узел"); + ОтправитьОшибкиПравилНаУдаленныйУзел(); + КонецЕсли; + Возврат ЭтотОбъект; + +КонецФункции + +// Переопределяет контекст сохранения +// +// Параметры: +// ПутьФайла - Строка - путь до файла контекста +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ПереопределитьКонтекстСохранения(ПутьФайла = "") Экспорт + НовыйКонтекст = ПолучитьПереопределенныйКонтекст(ПутьФайла); + Лог.Отладка("Переопределеяем контекст сохранения"); + ПараметрыПриложения.УстановитьКонтекстСохранения(НовыйКонтекст); + Возврат ЭтотОбъект; +КонецФункции + +// Переопределяет контекст сохранения ошибок +// +// Параметры: +// ПутьФайла - Строка - путь до файла контекста ошибок +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ПереопределитьКонтекстСохраненияОшибок(ПутьФайла = "") Экспорт + НовыйКонтекст = ПолучитьПереопределенныйКонтекст(ПутьФайла); + Лог.Отладка("Переопределеяем контекст сохранения ошибок"); + ПараметрыПриложения.УстановитьКонтекстСохраненияОшибок(НовыйКонтекст); + Возврат ЭтотОбъект; +КонецФункции + +// Записывает правила из результата запроса в файл +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ЗаписатьПравилаВФайл() Экспорт + ПутьФайла = ПараметрыПриложения.ПолучитьКонтекст(); + ФайловыеОперации.СоздатьСтруктуруКаталоговФайла(ПутьФайла, Истина); + ФайловыеОперации.ЗаписатьОбъект(ПутьФайла, ПравилаJSON); + Лог.Отладка("Файл правил записан по пути контекста %1", ПутьФайла); + Возврат ЭтотОбъект; +КонецФункции + +// Записывает ошибки правил из результата запроса в файл +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ЗаписатьОшибкиПравилВФайл() Экспорт + ПутьФайла = ПараметрыПриложения.ПолучитьКонтекстОшибок(); + ФайловыеОперации.СоздатьСтруктуруКаталоговФайла(ПутьФайла, Истина); + ФайловыеОперации.ЗаписатьОбъект(ПутьФайла, ОшибкиJSON); + Лог.Отладка("Файл ошибок правил записан по пути контекста %1", ПутьФайла); + Возврат ЭтотОбъект; +КонецФункции + +Функция НайтиОтличияОшибокПравилСУдаленногоУзлаИОшибокПравилКонтекста() Экспорт + + КонтекстОшибокПравил = ПараметрыПриложения.ПолучитьКонтекстОшибок(); + ПутьФайлКонтекстаОшибокПравил = ФайловыеОперации.ПолучитьКорректныйПутьФайла(КонтекстОшибокПравил); + ТекущийОбъектОшибокПравил = ФайловыеОперации.ПрочитатьОбъект(ПутьФайлКонтекстаОшибокПравил, Ложь); + ОшибкиПравилУУ = ОшибкиJSON; + ОшибкиПравилК = ТекущийОбъектОшибокПравил; + + МассивОтличий = ПолучитьОтличияДвухМассивоСтруктурПоКлючу(ОшибкиПравилУУ, ОшибкиПравилК, "ИсходнаяСтрока"); + + Для Каждого Элемент Из МассивОтличий Цикл + КодПравила = Элемент.КодПравила; + СтрокаОшибки = Элемент.ИсходнаяСтрока; + Лог.Отладка("Найдена ошибка в строке: %2%1(код правила: '%3')", Символы.ПС, СтрокаОшибки, КодПравила); + КонецЦикла; + + Возврат МассивОтличий.Количество() > 0; +КонецФункции + +// Возвращает результат проверки отличия правил контекста и правил, +// полученных с удаленного узла +// +// Возвращаемое значение: +// Булево - Истина, если найдены отличия по первому совпадению +Функция НайтиОтличияПравилСУдаленногоУзлаИПравилКонтекста() Экспорт + + КонтекстПравил = ПараметрыПриложения.ПолучитьКонтекст(); + ПутьФайлКонтекстаПравил = ФайловыеОперации.ПолучитьКорректныйПутьФайла(КонтекстПравил); + ТекущийОбъектПравил = ФайловыеОперации.ПрочитатьОбъект(ПутьФайлКонтекстаПравил, Ложь); + ПравилаУУ = ПравилаJSON.Rules; + ПравилаК = ТекущийОбъектПравил.Rules; + + МассивОтличий = ПолучитьОтличияДвухМассивоСтруктурПоКлючу(ПравилаУУ, ПравилаК, "Code"); + + Для Каждого Элемент Из МассивОтличий Цикл + Лог.Отладка("Найден отсутствующий код правил: '%1'", Элемент.Code); + КонецЦикла; + + Возврат МассивОтличий.Количество() > 0; + +КонецФункции + + +#КонецОбласти + + + + +#Область СлужебныеПроцедурыИФункции + + + +#Область ЗаполнениеПараметровСтруктурыURI + +// Инициализирует основные ключи для параметров структуры URI +// +// Перечень ключей структуры: +// * Cтруктура: +// * * Схема - Строка - http/https +// * * Логин - Строка - имя пользователя +// * * Пароль - Строка - пароль пользователя +// * * Токен - Строка - (не реализовано) Baerer-токен +// * * ИмяСервера - Строка - имя сервера (базовый URL) +// * * Хост - Строка - имя удаленного хоста +// * * Порт - Строка - порт удаленного хоста +// * * ПутьНаСервере - Строка - путь до ресурса на удаленном хосте +// * * ИмяФайлаНаСервере - Строка - имя ресурса (файла) на удаленном хосте +// * * ПолныйАдресРесурса - Строка - полный адрес с учетом пути до ресурса +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ИнициализироватьСтруктуруURI() + СтруктураURI = Новый Структура; + СтруктураURI.Вставить("Схема", ""); + СтруктураURI.Вставить("Логин", ""); + СтруктураURI.Вставить("Пароль", ""); + СтруктураURI.Вставить("Токен", ""); + СтруктураURI.Вставить("ИмяСервера", ""); + СтруктураURI.Вставить("Хост", ""); + СтруктураURI.Вставить("Порт", ""); + СтруктураURI.Вставить("ПутьНаСервере", ""); + СтруктураURI.Вставить("ИмяФайлаНаСервере", ""); + СтруктураURI.Вставить("ПолныйАдресРесурса", ""); + Возврат ЭтотОбъект; +КонецФункции + +// Выполняет заполнение инициализированной структуры с параметрами URI +// +// Параметры: +// ПолныйАдресРесурса - Строка - полный путь (ссылка на удаленный файл) +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ЗаполнитьБазовыеПараметрыСтруктурыURI(ПолныйАдресРесурса) + + СтрокаURI = СокрЛП(ПолныйАдресРесурса); + + // схема + Схема = ""; + Позиция = СтрНайти(СтрокаURI, "://"); + Если Позиция > 0 Тогда + Схема = НРег(Лев(СтрокаURI, Позиция - 1)); + СтрокаURI = Сред(СтрокаURI, Позиция + 3); + КонецЕсли; + + // строка соединения, путь и имя файла на сервере + СтрокаСоединения = СтрокаURI; + ПутьНаСервере = ""; + ИмяФайлаНаСервере = ""; + Позиция = СтрНайти(СтрокаСоединения, "/"); + Если Позиция > 0 Тогда + ПутьНаСервере = Сред(СтрокаСоединения, Позиция + 1); + СтрокаСоединения = Лев(СтрокаСоединения, Позиция - 1); + Позиция = СтрНайти(ПутьНаСервере, "/", НаправлениеПоиска.СКонца); + ИмяФайлаНаСервере = ?(Позиция > 0, Прав(ПутьНаСервере, СтрДлина(ПутьНаСервере) - Позиция), ПутьНаСервере); + КонецЕсли; + + // информация пользователя и имя сервера + СтрокаАвторизации = ""; + ИмяСервера = СтрокаСоединения; + Позиция = СтрНайти(СтрокаСоединения, "@"); + Если Позиция > 0 Тогда + СтрокаАвторизации = Лев(СтрокаСоединения, Позиция - 1); + ИмяСервера = Сред(СтрокаСоединения, Позиция + 1); + КонецЕсли; + + // логин и пароль + Логин = СтрокаАвторизации; + Пароль = ""; + Позиция = СтрНайти(СтрокаАвторизации, ":"); + Если Позиция > 0 Тогда + Логин = Лев(СтрокаАвторизации, Позиция - 1); + Пароль = Сред(СтрокаАвторизации, Позиция + 1); + КонецЕсли; + + // хост и порт + Хост = ИмяСервера; + Порт = ""; + + Позиция = СтрНайти(ИмяСервера, ":"); + Если Позиция > 0 Тогда + Хост = Лев(ИмяСервера, Позиция - 1); + Порт = Сред(ИмяСервера, Позиция + 1); + КонецЕсли; + + Если НЕ ЗначениеЗаполнено(СтруктураURI) Тогда + ИнициализироватьСтруктуруURI(); + КонецЕсли; + + СтруктураURI.Схема = Схема; + + Если ЗначениеЗаполнено(Логин) Тогда + СтруктураURI.Логин = Логин; + КонецЕсли; + + Если ЗначениеЗаполнено(Пароль) Тогда + СтруктураURI.Пароль = Пароль; + КонецЕсли; + + СтруктураURI.ИмяСервера = ИмяСервера; + СтруктураURI.Хост = Хост; + СтруктураURI.Порт = ?(Порт <> "", Число(Порт), Неопределено); + СтруктураURI.ПутьНаСервере = ПутьНаСервере; + СтруктураURI.ИмяФайлаНаСервере = ИмяФайлаНаСервере; + СтруктураURI.ПолныйАдресРесурса = ПолныйАдресРесурса; + + Возврат ЭтотОбъект; + +КонецФункции + +// Выполняет заполнение учетных данных (логин, пароль) инициализированной структуры с параметрами URI +// +// Параметры: +// Логин - Строка - имя пользователя +// Пароль - Строка - пароль пользователя +// +Процедура ЗаполнитьПараметрыBasicAuth(Логин, Пароль) + + Если ЗначениеЗаполнено(Логин) Тогда + СтруктураURI.Логин = Логин; + КонецЕсли; + + Если ЗначениеЗаполнено(Пароль) Тогда + СтруктураURI.Пароль = Пароль; + КонецЕсли; + +КонецПроцедуры + +// Выполняет заполнение токена инициализированной структуры с параметрами URI +// +// Параметры: +// Токен - Строка - токен пользователя +// +Процедура ЗаполнитьПараметрыBaererToken(Токен) + + Если ЗначениеЗаполнено(Токен) Тогда + СтруктураURI.Токен = Токен; + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти + + + +#Область HTTP_RestAPI + +// Создает новый экземпляр класса HTTPСоединение +// * В качестве параметров по-умолчанию используется: +// * * Таймаут = 60 сек +// +// Возвращаемое значение: +// HTTPСоединение - экземпляр класса HTTPСоединение +// +Функция ПодготовитьHTTPСоединение() + + SSL = Неопределено; + Если СтруктураURI.Схема = "https" Тогда + SSL = Новый ЗащищенноеСоединениеOpenSSL; + КонецЕсли; + + Логин = ?(ЗначениеЗаполнено(СтруктураURI.Логин), СтруктураURI.Логин, Неопределено); + Пароль = ?(ЗначениеЗаполнено(СтруктураURI.Пароль), СтруктураURI.Пароль, Неопределено); + + HTTPСоединение = Новый HTTPСоединение(СтруктураURI.Хост, СтруктураURI.Порт, Логин, Пароль, , 60, SSL); + + Возврат HTTPСоединение; + +КонецФункции + +// Создает коллекцию заголовков для HTTP запроса +// +// Возвращаемое значение: +// Соответствие - коллекция заголовков +// +Функция ПодготовитьHTTPЗаголовоки() + + Логин = СтруктураURI.Логин; + Пароль = СтруктураURI.Пароль; + Токен = СтруктураURI.Токен; + + HTTPЗаголовки = Новый Соответствие; + HTTPЗаголовки.Вставить("User-Agent", "curl/7.79.1"); + HTTPЗаголовки.Вставить("accept", "application/json; charset=utf-8"); + + ЭтоБазоваяАутентификация = ЗначениеЗаполнено(Логин) И ЗначениеЗаполнено(Пароль); + ЭтоТокенАутентификация = НЕ ЭтоБазоваяАутентификация И ЗначениеЗаполнено(Токен); + + СтрокаАвторизации = Неопределено; + Если ЭтоБазоваяАутентификация Тогда + ДвоичныеДанные = ПолучитьДвоичныеДанныеИзСтроки(СтрШаблон("%1:%2", Логин, Пароль), КодировкаТекста.UTF8, Ложь); + СтрокаАвторизации = ПолучитьBase64СтрокуИзДвоичныхДанных(ДвоичныеДанные); + Лог.Отладка("Аутентификация по логину и паролю"); + HTTPЗаголовки.Вставить("Authorization", "Basic " + СтрокаАвторизации); + ИначеЕсли ЭтоТокенАутентификация Тогда + Лог.Отладка("Аутентификация по токену"); + HTTPЗаголовки.Вставить("Authorization", "Bearer " + Токен); + Иначе + Лог.Отладка("Анонимная аутентификация"); + КонецЕсли; + + Возврат HTTPЗаголовки; + +КонецФункции + +// Создает новый экземпляр класса HTTPЗапрос +// * Если используются методы отличные от DELETE и GET, то в запрос добавляется строка с телом запроса +// +// Параметры: +// ИмяМетода - Строка - имя REST-метода +// HTTPЗаголовки - Соответствие, Неопределено - коллекция заголовков +// СтрокаТелаЗапроса - Строка - Тело запроса +// НовыйПутьНаСервере - Строка - Специфический путь на сервере +// +// Возвращаемое значение: +// HTTPЗапрос - экземпляр класса HTTPЗапрос +// +Функция ПодготовитьHTTPЗапрос(ИмяМетода, HTTPЗаголовки = Неопределено, СтрокаТелаЗапроса = "", НовыйПутьНаСервере = "") + + ПутьНаСервере = СтруктураURI.ПутьНаСервере; // Путь на сервере по-умолчанию + + Если ЗначениеЗаполнено(СокрЛП(НовыйПутьНаСервере)) Тогда + ПутьНаСервере = НовыйПутьНаСервере; + КонецЕсли; + + HTTPЗапрос = Новый HTTPЗапрос(ПутьНаСервере, HTTPЗаголовки); + Если ИмяМетода <> "DELETE" И ИмяМетода <> "GET" Тогда + HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаТелаЗапроса); + КонецЕсли; + Возврат HTTPЗапрос; +КонецФункции + +// Выполняет HTTPЗапрос +// +// Параметры: +// HTTPЗапрос - HTTPЗапрос - запрос, который нужно выполнить +// ИмяМетода - Строка - имя REST-метода +// +// Возвращаемое значение: +// HTTPРезультат - результат выполнения HTTPЗапроса +// +Функция ВыполнитьHTTPЗапрос(HTTPЗапрос, ИмяМетода) + РезультатЗапроса = Неопределено; + HTTPСоединение = ПодготовитьHTTPСоединение(); + Попытка + РезультатЗапроса = HTTPСоединение.ВызватьHTTPМетод(ИмяМетода, HTTPЗапрос); + ТелоРезультата = РезультатЗапроса.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8); + Лог.Отладка(СтрШаблон("Результат HTTP запроса:%1%2", Символы.ПС, ТелоРезультата)); + Исключение + Лог.КритичнаяОшибка(ОписаниеОшибки()); + ВызватьИсключение; + КонецПопытки; + Возврат РезультатЗапроса; +КонецФункции + +// Анализирует типы кодов состояния от HTTPРезультата +// и выводит информацию в лог Предупреждений/Отладки/Ошибок +// +// Параметры: +// РезультатЗапроса - HTTPРезультат - результат запроса +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ПроанализироватьКодСостоянияРезультата(РезультатЗапроса) + + КодСостояния = РезультатЗапроса.КодСостояния; + + ОбработатьКодСостоянияОшибкиКлиента(КодСостояния); + ОбработатьКодСостоянияОшибкиСервера(КодСостояния); + ОбработатьКодСостоянияПеренаправлений(КодСостояния); + ОбработатьКодСостоянияУспешныхОтветов(КодСостояния); + ОбработатьКодСостоянияИнформационныхСообщений(КодСостояния); + + Возврат ЭтотОбъект; + +КонецФункции + +// Получает тело результата запроса +// +// Параметры: +// РезультатЗапроса - HTTPРезультат - результат выполнения запроса +// +// Возвращаемое значение: +// Строка - тело результата запроса +// +Функция ПолучитьТелоРезультатаЗапроса(РезультатЗапроса) + + Если Не ЗначениеЗаполнено(РезультатЗапроса) Тогда + Лог.Ошибка("Отсутствует результат запроса. Дальнейшая работа невозможна!"); + ВызватьИсключение("Результат запроса отсутствует или пустой!"); + КонецЕсли; + + ТелоЗапроса = РезультатЗапроса.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8); + Если Не ЗначениеЗаполнено(ТелоЗапроса) Тогда + Лог.Предупреждение("Отсутствует тело запроса"); + КонецЕсли; + + Возврат ТелоЗапроса; + +КонецФункции + +// Инициалзирует переменную ПравилаJSON +// В эту переменную записывается объекта JSON из тела результата запроса +// * функция заполняет значение, только если оно отсутствует в переменной +// +// Параметры: +// РезультатЗапроса - HTTPРезультат - результат запроса +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ИнициализироватьОбъектПравилИзТелаРезультатаЗапроса(РезультатЗапроса) + Если Не ЗначениеЗаполнено(ПравилаJSON) Тогда + ТелоЗапроса = ПолучитьТелоРезультатаЗапроса(РезультатЗапроса); + Если ЗначениеЗаполнено(ТелоЗапроса) Тогда + ПравилаJSON = ФайловыеОперации.ПолучитьОбъектИзСтрокиJSON(ТелоЗапроса); + КонецЕсли; + КонецЕсли; + Возврат ЭтотОбъект; +КонецФункции + +// Инициалзирует переменную ОшибкиJSON +// В эту переменную выполняется запись объекта JSON из тела результата запроса +// * функция заполняет значение, только если оно отсутствует в переменной +// +// Параметры: +// РезультатЗапроса - HTTPРезультат - результат запроса +// +// Возвращаемое значение: +// ЗагрузчикПравил - объект загрузчика правил +// +Функция ИнициализироватьОбъектОшибокПравилИзТелаРезультатаЗапроса(РезультатЗапроса) + Если Не ЗначениеЗаполнено(ОшибкиJSON) Тогда + ТелоЗапроса = ПолучитьТелоРезультатаЗапроса(РезультатЗапроса); + Если ЗначениеЗаполнено(ТелоЗапроса) Тогда + ОшибкиJSON = ФайловыеОперации.ПолучитьОбъектИзСтрокиJSON(ТелоЗапроса); + КонецЕсли; + КонецЕсли; + Возврат ЭтотОбъект; +КонецФункции + +// Проверяет соответствие кода результата перечню допустимых кодов +// +// Параметры: +// КодСостояния - Целом - код состояния, который нужно проверить +// +// Возвращаемое значение: +// Булево - Если Истина, код состояния прошёл проверку по допустимым кодам +// +Функция ЭтоДопустимыйКодСостоянияРезультата(КодСостояния) + Если Не ТипЗнч(КодСостояния) = Тип("Число") Тогда + Возврат Ложь; + КонецЕсли; + + ДопустимыеКодыСостояния = Новый Массив; + ДопустимыеКодыСостояния.Добавить(200); + ДопустимыеКодыСостояния.Добавить(201); + ДопустимыеКодыСостояния.Добавить(202); + + Возврат Не ДопустимыеКодыСостояния.Найти(КодСостояния) = Неопределено; + +КонецФункции + +#КонецОбласти + + + +#Область HTTP_RestStatusCodes + +// Сообщает ошибку по коду состояния +// * коды состояния 100-199 (информационные ответы) +// +// Параметры: +// КодСостояния - Число - Код состояния результата запроса +// +Процедура ОбработатьКодСостоянияИнформационныхСообщений(КодСостояния) + Если КодСостояния >= 100 И КодСостояния < 200 Тогда + Лог.Отладка("Код состояния больше 1ХХ, информационный ответ. Код состояния: " + КодСостояния); + КонецЕсли; +КонецПроцедуры + +// Сообщает ошибку по коду состояния +// * коды состояния 200-299 (успешные ответы) +// +// Параметры: +// КодСостояния - Число - Код состояния результата запроса +// +Процедура ОбработатьКодСостоянияУспешныхОтветов(КодСостояния) + Если КодСостояния >= 200 И КодСостояния < 300 Тогда + Лог.Отладка("Код состояния больше 2ХХ, успешный ответ. Код состояния: " + КодСостояния); + КонецЕсли; +КонецПроцедуры + +// Сообщает ошибку по коду состояния +// * коды состояния 300-399 (перенаправление) +// +// Параметры: +// КодСостояния - Число - Код состояния результата запроса +// +Процедура ОбработатьКодСостоянияПеренаправлений(КодСостояния) + Если КодСостояния >= 300 И КодСостояния < 400 Тогда + Лог.Ошибка("Код состояния больше 3XX, Перенаправление. Код состояния: " + КодСостояния); + КонецЕсли; +КонецПроцедуры + +// Сообщает ошибку по коду состояния +// * коды состояния 400-499 (ошибки клиента) +// +// Параметры: +// КодСостояния - Число - Код состояния результата запроса +// +Процедура ОбработатьКодСостоянияОшибкиКлиента(КодСостояния) + Если КодСостояния >= 400 И КодСостояния < 500 Тогда + Лог.Ошибка("Код состояния больше 4XX, ошибка клиента. Код состояния: " + КодСостояния); + КонецЕсли; +КонецПроцедуры + +// Сообщает ошибку по коду состояния +// * коды состояния 500-599 (ошибки сервера) +// +// Параметры: +// КодСостояния - Число - Код состояния результата запроса +// +Процедура ОбработатьКодСостоянияОшибкиСервера(КодСостояния) + Если КодСостояния >= 500 И КодСостояния < 600 Тогда + Лог.Ошибка("Код состояния больше 5XX, ошибка сервера. Код состояния: " + КодСостояния); + КонецЕсли; +КонецПроцедуры + +#КонецОбласти + + + +#Область Специфические + +// Переопределяет путь файла контекста +// * Используется для того, чтобы изменения файла контекста выполнялись по отдельному пути +// +// Параметры: +// ПереопределяемыйКонтекст - Строка - путь до файла контекста +// +// Возвращаемое значение: +// Строка - переопределенный путь до файла контекст +// +Функция ПолучитьПереопределенныйКонтекст(ПереопределяемыйКонтекст) + КорректныйПутьКонтекста = ФайловыеОперации.ПолучитьКорректныйПутьФайла(ПереопределяемыйКонтекст); + ПутьУказан = ЗначениеЗаполнено(КорректныйПутьКонтекста); + ИмяФайла = ФайловыеОперации.ПолучитьИмяФайла(КорректныйПутьКонтекста); + ПутьКонтекстаПоУмолчанию = СтрШаблон("./.rules/%1", ИмяФайла); + ПереопределенныйКонтекст = ?(ПутьУказан, КорректныйПутьКонтекста, ПутьКонтекстаПоУмолчанию); + Возврат ПереопределенныйКонтекст; +КонецФункции + +// Создает копию структуры URI с новыми параметрами +// +// Параметры: +// СтруктураURI - Структура - структура параметров URI +// НовыйПутьНаСервере - Строка - новый путь на сервере (за исключением имени конечного файла) +// НовоеИмяФайла - Строка - новое имя файла +// +// Возвращаемое значение: +// Структура - Новая структура URI +// +Функция СоздатьКопиюСтруктурыURI(СтруктураURI, НовыйПутьНаСервере = "", НовоеИмяФайла = "") + + НоваяСтруктураURI = СкопироватьСтруктуру(СтруктураURI); + + ИзменитьИмяФайла = ЗначениеЗаполнено(СокрЛП(НовоеИмяФайла)); + ИзменитьПутьНаСервере = ЗначениеЗаполнено(СокрЛП(НовыйПутьНаСервере)); + + ИмяФайлаНаСервере = НоваяСтруктураURI.ИмяФайлаНаСервере; + ПутьНаСервере = НоваяСтруктураURI.ПутьНаСервере; + + НоваяСтруктураURI.ИмяФайлаНаСервере = НовоеИмяФайла; + + Для Каждого ПараметрURI из НоваяСтруктураURI Цикл + Ключ = ПараметрURI.Ключ; + Значение = ПараметрURI.Значение; + // 1. Меняем путь + Если ИзменитьПутьНаСервере И СтрНайти(Значение, ПутьНаСервере, НаправлениеПоиска.СНачала) > 0 Тогда + НоваяСтруктураURI[Ключ] = СтрЗаменить(Значение, ПутьНаСервере, НовыйПутьНаСервере); + КонецЕсли; + + // 2. Меняем имя + Если ИзменитьИмяФайла И СтрНайти(Значение, ИмяФайлаНаСервере, НаправлениеПоиска.СНачала) > 0 Тогда + НоваяСтруктураURI[Ключ] = СтрЗаменить(Значение, ИмяФайлаНаСервере, НовоеИмяФайла); + КонецЕсли; + КонецЦикла; + + Возврат НоваяСтруктураURI; + +КонецФункции + +// Устанавливает уникальное имя файла в замен уже существующему в структуре параметров URI +// * При этом обновляются взимосвязанные значения +// +Процедура УстановитьУникальноеИмяФайлаПравил() + + Контекст = ПараметрыПриложения.ПолучитьКонтекст(); + + ДатаВМиллисекундах = Строка(ТекущаяУниверсальнаяДатаВМиллисекундах()); + ГУИД = СтрЗаменить(Строка(Новый УникальныйИдентификатор()), "-", ""); + ИмяФайлаБезРасширения = ФайловыеОперации.ИмяБезРасширения(Контекст); + УникальноеИмя = СтрШаблон("%1_%2_%3.json", ИмяФайлаБезРасширения, ГУИД, ДатаВМиллисекундах); + + НоваяСтруктураURI = СоздатьКопиюСтруктурыURI(СтруктураURI, "", УникальноеИмя); + + СтруктураURI = НоваяСтруктураURI; + +КонецПроцедуры + +// Проверяет наличие (заполненность) переменной "СтруктураURI" +// В ином случае - возвращает исключение +Процедура ПроверитьНаличиеСтруктурыURI() + Если НЕ ЗначениеЗаполнено(СтруктураURI) Тогда + ВызватьИсключение "Не выполнена инициализация параметров структуры URI!"; + КонецЕсли; +КонецПроцедуры + +// Копирует структуру, указанную в параметре +// +// Параметры: +// КопируемаяСтруктура - Структура - структура, которую нужно скопировать +// +// Возвращаемое значение: +// Структура - скопированная структура +// +Функция СкопироватьСтруктуру(КопируемаяСтруктура) + КопияСтруктуры = Новый Структура; + Если Не ТипЗнч(КопируемаяСтруктура) = Тип("Структура") Тогда + ВызватьИсключение "Невозможно скопировать структуру. Тип входящего параметра не соответветствует типу 'Структура'"; + КонецЕсли; + Для Каждого ЭлементСтруктуры Из КопируемаяСтруктура Цикл + КопияСтруктуры.Вставить(ЭлементСтруктуры.Ключ, ЭлементСтруктуры.Значение); + КонецЦикла; + Возврат КопияСтруктуры; +КонецФункции + +// Возвращает массив отличающихся структур между двумя массивами +// * Поиск отличий по указанному ключу +// +// Параметры: +// РодительскийМассив - Массив - массив, в котором происходить поиск по дочернему массиву +// ДочернийМассив - Массив - Массив, по которому будет выполняться поиск отличий +// ПроверяемыйКлюч - Строка - ключ структуры, по которому может выполняться проверка отличий (по-умолчанию: не задан) +// +// Возвращаемое значение: +// Массив - Массив отличающихся структур +// +Функция ПолучитьОтличияДвухМассивоСтруктурПоКлючу(РодительскийМассив, ДочернийМассив, ПроверяемыйКлюч) + + ОтличающиесяСтруктуры = Новый Массив; + + // На случай, когда в родительском массив нет элементов + // (по сути массивы отличаются целиком) + Если РодительскийМассив.Количество() = 0 Тогда + Возврат ДочернийМассив; + КонецЕсли; + + Для Каждого ЭлементДочернегоМассива Из ДочернийМассив Цикл + НайденоСовпадение = Ложь; + НайденныйКлючД = ""; + Если Не ЭлементДочернегоМассива.Свойство(ПроверяемыйКлюч, НайденныйКлючД) Тогда + Продолжить; + КонецЕсли; + Для Каждого ЭлементРодительскогоМассива Из РодительскийМассив Цикл + НайденныйКлючР = ""; + Если Не ЭлементРодительскогоМассива.Свойство(ПроверяемыйКлюч, НайденныйКлючР) Тогда + Продолжить; + КонецЕсли; + Если НРег(СокрЛП(НайденныйКлючД)) = НРег(СокрЛП(НайденныйКлючР)) Тогда + НайденоСовпадение = Истина; + КонецЕсли; + КонецЦикла; + Если Не НайденоСовпадение Тогда + ОтличающиесяСтруктуры.Добавить(ЭлементДочернегоМассива); + КонецЕсли; + КонецЦикла; + + Возврат ОтличающиесяСтруктуры; + +КонецФункции + +#КонецОбласти + + + +#КонецОбласти + + +Лог = ПараметрыПриложения.Лог(); \ No newline at end of file diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\202\321\207\320\265\321\202\320\260\320\225\320\224\320\242.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\202\321\207\320\265\321\202\320\260\320\225\320\224\320\242.os" index d2862bf..b037998 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\202\321\207\320\265\321\202\320\260\320\225\320\224\320\242.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\202\321\207\320\265\321\202\320\260\320\225\320\224\320\242.os" @@ -1,26 +1,28 @@ -Процедура ОписаниеКоманды(Команда) Экспорт +Перем Лог; // Переменная для хранения логов - Команда.Аргумент("PATH", "", "Файл с отчетом") - .ТСтрока(); +Процедура ОписаниеКоманды(Знач КомандаПриложения) Экспорт + + КомандаПриложения.Опция("nixPath", Истина, "Использовать пути как в линукс системах") + .ТБулево() + .ВОкружении("EDT_RIPPER_USE_UNIX_PATHS"); - Команда.Аргумент("WORKDIR", "", "Корень репозитория или проектной области") - .ТСтрока(); + КомандаПриложения.Аргумент("PATH", "", "Файл с отчетом") + .ТСтрока(); - Команда.Аргумент("PROJECTS", Новый Массив, "Список проектов, которые были переданы в ЕДТ для анализа") - .ТМассивСтрок(); + КомандаПриложения.Аргумент("WORKDIR", "", "Корень репозитория или проектной области") + .ТСтрока(); - Команда.Аргумент("OUT", "", "Путь к файлу отчета в формате BSL LS") - .ТСтрока(); + КомандаПриложения.Аргумент("PROJECTS", Новый Массив, "Список проектов, которые были переданы в ЕДТ для анализа") + .ТМассивСтрок(); - Команда.Опция("nixPath", Истина, "Использовать пути как в линукс системах") - .ТБулево(); + КомандаПриложения.Аргумент("OUT", "", "Путь к файлу отчета в формате BSL LS") + .ТСтрока(); КонецПроцедуры Процедура ПередВыполнениемКоманды(Знач Команда) Экспорт Лог = ПараметрыПриложения.Лог(); - БылиОшибки = Ложь; ФайлДляОбработки = Новый Файл(Команда.ЗначениеАргумента("PATH")); @@ -64,6 +66,26 @@ ФайлРезультата = Команда.ЗначениеАргумента("OUT"); ПутиКакВЛинукс = Команда.ЗначениеОпции("nixPath"); - ПарсерОшибок.Прочитать(ФайлДляОбработки, Репозиторий, Проекты, ФайлРезультата, ПутиКакВЛинукс); + Парсер = ПарсерОшибок.ПолучитьОбъект(); + + // Запись и дополнение контекста + Парсер.Прочитать(ФайлДляОбработки, Репозиторий, Проекты, ФайлРезультата, ПутиКакВЛинукс); + + // Запись ошибок правил + Если ПараметрыПриложения.ПолучитьРежимЗаписиОшибокПравил() И Парсер.ПроверитьНаличиеОшибокПравил() Тогда + КонтекстОшибок = ПараметрыПриложения.ПолучитьКонтекстОшибок(); + ФайловыеОперации.ЗаписатьОбъект(КонтекстОшибок, Парсер.ПолучитьОшибкиПравил()); + Лог.Информация("Записан файл ошибок %1", КонтекстОшибок); + КонецЕсли; + + // Отправка измененых файлов на удаленный узел + ЗагрузчикПравил = ПараметрыПриложения.ПолучитьЗагрузчикПравил(Ложь); + Если ЗначениеЗаполнено(ЗагрузчикПравил) Тогда + // Отправка файла правил + ЗагрузчикПравил.ОтправитьПравилаНаУдаленныйУзел(Истина); + // Отправка файла ошибок правил + ЗагрузчикПравил.ОтправитьОшибкиПравилНаУдаленныйУзел(Истина); + КонецЕсли; + Лог.Информация("Команда выполнена"); КонецПроцедуры diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\237\321\203\320\261\320\273\320\270\320\272\320\260\321\206\320\270\321\217\320\237\321\200\320\260\320\262\320\270\320\273.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\237\321\203\320\261\320\273\320\270\320\272\320\260\321\206\320\270\321\217\320\237\321\200\320\260\320\262\320\270\320\273.os" index b0109f4..c65209d 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\237\321\203\320\261\320\273\320\270\320\272\320\260\321\206\320\270\321\217\320\237\321\200\320\260\320\262\320\270\320\273.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\237\321\203\320\261\320\273\320\270\320\272\320\260\321\206\320\270\321\217\320\237\321\200\320\260\320\262\320\270\320\273.os" @@ -1,3 +1,4 @@ +Перем Лог; Процедура ОписаниеКоманды(Команда) Экспорт Команда.Аргумент("OUT", "", "Путь к файлу отчета в формате BSL LS") @@ -5,10 +6,25 @@ КонецПроцедуры +Процедура ПередВыполнениемКоманды(Знач Команда) Экспорт + + Лог = ПараметрыПриложения.Лог(); + ПутьФайлаРезультатов = Команда.ЗначениеАргумента("OUT"); + КорректныйПутьФайлаРезультатов = ФайловыеОперации.ПолучитьКорректныйПутьФайла(ПутьФайлаРезультатов); + Если Не ФайловыеОперации.ПроверитьСуществованиеФайла(КорректныйПутьФайлаРезультатов) Тогда + Лог.Ошибка("Отсуствует файл результата"); + ВызватьИсключение("Дальнейшая работа невозможна"); + КонецЕсли; + +КонецПроцедуры + Процедура ВыполнитьКоманду(Знач Команда) Экспорт - + ФайлРезультата = Команда.ЗначениеАргумента("OUT"); ХранилищеПравил = Новый ХранилищеПравил; + ХранилищеПравил.Опубликовать(ФайлРезультата); + Лог.Информация("Команда выполнена"); + КонецПроцедуры diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\321\200\320\276\320\265\320\272\321\202.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\321\200\320\276\320\265\320\272\321\202.os" index 133aa99..26d235e 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\321\200\320\276\320\265\320\272\321\202.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\321\200\320\276\320\265\320\272\321\202.os" @@ -1,7 +1,7 @@ #Использовать fs #Область ОписаниеПеременных -Перем ПутьПроекта; +Перем ПутьПроекта; // Путь до проекта #КонецОбласти @@ -19,7 +19,7 @@ ИначеЕсли ЭтоКонфигуратор() Тогда Возврат ПутьПроекта; Иначе - ВызватьИсключение "Невозможно найти путь исходников, не определена структура выгрузки" + ВызватьИсключение "Невозможно найти путь исходников, не определена структура выгрузки"; КонецЕсли; КонецФункции @@ -74,6 +74,10 @@ КонецФункции +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + Функция ЭтоКонфигураторКонфигурацияИлиРасширение() СодержитФайлОписания = НайтиФайлы(ПутьПроекта(), "Configuration.xml").Количество(); @@ -91,10 +95,10 @@ КонецФункции -#КонецОбласти - Процедура ПриСозданииОбъекта(Путь) ПутьПроекта = Путь; КонецПроцедуры + +#КонецОбласти \ No newline at end of file diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\245\321\200\320\260\320\275\320\270\320\273\320\270\321\211\320\265\320\237\321\200\320\260\320\262\320\270\320\273.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\245\321\200\320\260\320\275\320\270\320\273\320\270\321\211\320\265\320\237\321\200\320\260\320\262\320\270\320\273.os" index 9593169..ea31560 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\245\321\200\320\260\320\275\320\270\320\273\320\270\321\211\320\265\320\237\321\200\320\260\320\262\320\270\320\273.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\245\321\200\320\260\320\275\320\270\320\273\320\270\321\211\320\265\320\237\321\200\320\260\320\262\320\270\320\273.os" @@ -1,7 +1,9 @@ +#Использовать fs + #Область ОписаниеПеременных -// Хранилище правилы -Перем Правила; +Перем Правила; // Хранилище правил + #КонецОбласти #Область ПрограммныйИнтерфейс @@ -46,7 +48,7 @@ КонецЦикла; - ЗаписатьОбъект(ПараметрыПриложения.ПолучитьКонтекст(), Объект); + ФайловыеОперации.ЗаписатьОбъект(ПараметрыПриложения.ПолучитьКонтекст(), Объект); КонецПроцедуры @@ -75,7 +77,12 @@ КонецЦикла; - ЗаписатьОбъект(Путь, Объект); + КорректныйПуть = ФайловыеОперации.ПолучитьКорректныйПутьФайла(Путь); + АбсолютныйПуть = ФС.ПолныйПуть(КорректныйПуть); + + ФайловыеОперации.ЗаписатьОбъект(АбсолютныйПуть, Объект); + + ПараметрыПриложения.Лог().Информация("Опубликован файл результата: %1", АбсолютныйПуть); КонецПроцедуры @@ -114,18 +121,18 @@ // Возвращаемое значение: // Строка - Имя правила, пригодное для экспорта в SQ // -Функция НормализоватьИмяПравила(ЗНАЧ Имя) Экспорт +Функция НормализоватьИмяПравила(Знач Имя) Экспорт - //На SQ ограничение 200 - но мы смотрим просто что оно очень длинное - МаксимальнаяДлиннаИмениПравила = 150; + // На SQ ограничение 200 - но мы смотрим просто что оно очень длинное + МаксимальнаяДлина = ПолучитьМаксимальнуюДлинуИмениПравила(); - Если СтрДлина(Имя) > МаксимальнаяДлиннаИмениПравила Тогда + Если СтрДлина(Имя) > МаксимальнаяДлина Тогда ЧастиИмени = СтрРазделить(Имя, ".", Ложь); - Если СтрДлина(ЧастиИмени[0]) > МаксимальнаяДлиннаИмениПравила Тогда + Если СтрДлина(ЧастиИмени[0]) > МаксимальнаяДлина Тогда - Имя = Лев(ЧастиИмени[0], МаксимальнаяДлиннаИмениПравила - 1 ); + Имя = Лев(ЧастиИмени[0], МаксимальнаяДлина - 1 ); Иначе @@ -140,29 +147,27 @@ #КонецОбласти -Процедура ЗаписатьОбъект(ПутьКФайлу, ОбъектЗаписи) +#Область СлужебныйПрограммныйИнтерфейс - ЗаписьJSON = Новый ЗаписьJSON; - ЗаписьJSON.ОткрытьФайл(ПутьКФайлу, "UTF-8", , Новый ПараметрыЗаписиJSON(, Символы.Таб)); - ЗаписатьJSON(ЗаписьJSON, ОбъектЗаписи); - ЗаписьJSON.Закрыть(); - -КонецПроцедуры +// Возвращает максимальную длину имени правила +// * У SonarQube есть ограничение по длине имени правила, равное 200 символов +// * Поэтому вводим доп. ограничение, чуть меньше, чем ограничение SonarQube +// +// Возвращаемое значение: +// Целое - длина имени правила +// +Функция ПолучитьМаксимальнуюДлинуИмениПравила() Экспорт + МаксимальнаяДлиннаИмениПравила = 150; + Возврат МаксимальнаяДлиннаИмениПравила; +КонецФункции -Функция ПрочитатьОбъект(ИмяФайла) +#КонецОбласти - ЧтениеJSON = Новый ЧтениеJSON; - ЧтениеJSON.ОткрытьФайл(ИмяФайла, "UTF-8"); - Объект = ПрочитатьJSON(ЧтениеJSON, Ложь); - ЧтениеJSON.Закрыть(); - Возврат Объект; +#Область СлужебныеПроцедурыИФункции -КонецФункции Функция ПравилаКакОбъект() - - Возврат ПрочитатьОбъект(ПараметрыПриложения.ПолучитьКонтекст()); - + Возврат ФайловыеОперации.ПрочитатьОбъект(ПараметрыПриложения.ПолучитьКонтекст(), Ложь); КонецФункции Процедура ПриСозданииОбъекта() @@ -177,3 +182,7 @@ Правила = Новый Структура("ПоКоду", ПоКоду); КонецПроцедуры + + +#КонецОбласти + diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" index af5c726..3e851fc 100644 --- "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" +++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" @@ -1,10 +1,13 @@ +#Использовать fs #Использовать logos #Область ОписаниеПеременных - -Перем Лог; -Перем Контекст; +Перем Лог; // Переменная для хранения логов +Перем Контекст; // Контекст (путь до файла с правилами)) +Перем КонтекстОшибок; // Имя файла ошибок при проверке по правилам "rule-errors.log" +Перем ЗагрузчикПравил; // Инстанс загрузчика правил +Перем ЗаписьОшибокПравил; // Запись ошибок правил в файл (Истина/Ложь) #КонецОбласти @@ -25,39 +28,75 @@ КонецФункции +// Возвращает контекст сохранения замечаний +// +// Возвращаемое значение: +// Строка - контекст для работы с сохранением правил +// +Функция ПолучитьКонтекст() Экспорт + + Если Не ЗначениеЗаполнено(Контекст) Тогда + Лог.Отладка("Установка котекста сохранения замечаний"); + УстановитьКонтекстСохранения(Неопределено); + КонецЕсли; + + Возврат Контекст; + +КонецФункции + // Устанавливает место, откуда будут читаться старые замечания и записываться новые. // // Параметры: // ПутьКФайлу - Строка - Путь к внешнему файлу правил // Процедура УстановитьКонтекстСохранения(Знач ПутьКФайлу) Экспорт - - Если ЗначениеЗаполнено(ПутьКФайлу) Тогда - Контекст = ПутьКФайлу; + ТипКонтекста = ?(ЗначениеЗаполнено(Контекст), "новый", ""); + + Если ЗначениеЗаполнено(ПутьКФайлу) Тогда + Контекст = ФС.ПолныйПуть(ПутьКФайлу); + Сообщение = СтрШаблон("Установлен %1 контекст сохранения замечаний: %2", ТипКонтекста, Контекст); + Лог.Информация(СтрЗаменить(Сообщение, " ", " ")); Иначе - Контекст = ЛокальныйКонтекст(); + Контекст = ФС.ПолныйПуть(ЛокальныйКонтекст()); + Лог.Информация("Установлен локальный контекст сохранения замечаний: %1", Контекст); КонецЕсли; - Лог().Информация("Установлен контекст сохранения замечаний %1", Контекст); - КонецПроцедуры -// Устанавливает способ сохранения замечаний и возвращает выбранный контекст +// Возвращает контекст сохранения ошибок // // Возвращаемое значение: -// Строка - контекст для работы с сохранением правил +// Строка - контекст ошибок // -Функция ПолучитьКонтекст() Экспорт +Функция ПолучитьКонтекстОшибок() Экспорт - Если Контекст = Неопределено Тогда - УстановитьКонтекстСохранения(Неопределено); + Если Не ЗначениеЗаполнено(КонтекстОшибок) Тогда + Лог.Отладка("Установка контекста сохранения ошибок"); + УстановитьКонтекстСохраненияОшибок(""); КонецЕсли; - Возврат Контекст; + Возврат КонтекстОшибок; КонецФункции +// Устанавливает путь до файла содержащего ошибки замечаний. +// +// Параметры: +// ПутьКФайлу - Строка - Путь к внешнему файлу ошибок замечаний +// +Процедура УстановитьКонтекстСохраненияОшибок(Знач ПутьКФайлу) Экспорт + + Если ЗначениеЗаполнено(ПутьКФайлу) Тогда + КонтекстОшибок = ФС.ПолныйПуть(ПутьКФайлу); + Лог.Информация("Установлен новый контекст сохранения ошибок: %1", КонтекстОшибок); + Иначе + КонтекстОшибок = ФС.ПолныйПуть(ЛокальныйКонтекстОшибок()); + Лог.Информация("Установлен локальный контекст сохранения ошибок: %1", КонтекстОшибок); + КонецЕсли; + +КонецПроцедуры + // Путь к локальному файлу с сохраненными правилами // // Возвращаемое значение: @@ -69,6 +108,17 @@ КонецФункции +// Путь к локальному файлу с ошибками замечаний +// +// Возвращаемое значение: +// Строка - Путь к файлу +// +Функция ЛокальныйКонтекстОшибок() Экспорт + + Возврат ОбъединитьПути(ТекущийСценарий().Каталог, "../..", "custom-rules-errors.json"); + +КонецФункции + // Возвращает имя лога приложения // // Возвращаемое значение: @@ -84,7 +134,6 @@ // Строка - Имя приложения // Функция ИмяПриложения() Экспорт - Возврат "edt-ripper"; КонецФункции @@ -116,4 +165,53 @@ КонецПроцедуры +// Получает экземпляр класса загрузчика правил +// +// Параметры: +// УчитыватьСозданиеНовогоЭкземпляра - Булево - Если Ложь, +// то при отсутствии экземпляра класса, будет создан новый, +// иначе - будет возвращено текущее значение +// +// Возвращаемое значение: +// ЗагрузчикПравил, Неопределено - возвращает объект загрузчика правил или неопределенное значение +// +Функция ПолучитьЗагрузчикПравил(УчитыватьСозданиеНовогоЭкземпляра = Истина) Экспорт + + Если Не ЗначениеЗаполнено(ЗагрузчикПравил) И УчитыватьСозданиеНовогоЭкземпляра Тогда + Лог.Информация("Используется 'Загрузчик правил'"); + ЗагрузчикПравил = Новый ЗагрузчикПравил; + Возврат ЗагрузчикПравил; + КонецЕсли; + + Возврат ЗагрузчикПравил; + +КонецФункции + +// Устанавливает режим записи ошибок правил в файл +// * Если "Истина" - ошибки правил будут записываться в файл, иначе - без записи в файл +// +// Параметры: +// РежимЗаписиОшибокПравил - Булево - (по-умолчанию - Ложь) +// +Процедура УстановитьРежимЗаписиОшибокПравил(РежимЗаписиОшибокПравил = Ложь) Экспорт + ЗаписьОшибокПравил = РежимЗаписиОшибокПравил; + Если РежимЗаписиОшибокПравил Тогда + Лог.Информация("Включен режим записи ошибок правил в файл"); + КонецЕсли; +КонецПроцедуры + +// Возвращает значение режима записи ошибок правил в файл +// +// Возвращаемое значение: +// Булево - Если, Истина - запись ошибок правил будет выполняться в файл +// +Функция ПолучитьРежимЗаписиОшибокПравил() Экспорт + Возврат ЗаписьОшибокПравил; +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + + #КонецОбласти diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\210\320\270\320\261\320\276\320\272.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\210\320\270\320\261\320\276\320\272.os" index 58e1512..5a39203 100644 --- "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\210\320\270\320\261\320\276\320\272.os" +++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\321\201\320\265\321\200\320\236\321\210\320\270\320\261\320\276\320\272.os" @@ -1,8 +1,10 @@ -#Область ОписаниеПеременных +#Использовать fs -Перем КешПрочитанныхФайлов; -Перем Лог; +#Область ОписаниеПеременных +Перем КешПрочитанныхФайлов; // Кеш прочитанных файлов +Перем Лог; // Переменная для хранения логов +Перем ОшибкиПравил; // Массив ошибок, возникающих в процессе парсинга #КонецОбласти #Область ПрограммныйИнтерфейс @@ -18,10 +20,10 @@ // Процедура Прочитать(Файл, ПутьКРепозиторию, СписокПроектов, ФайлРезультата, ПутиКакВЛинукс) Экспорт - Чтение = Новый ЧтениеТекста; + Чтение = Новый ЧтениеТекста(); Чтение.Открыть(Файл, "UTF-8", , , Ложь); - Строка = Чтение.ПрочитатьСтроку(); + ПрочитаннаяСтрока = Чтение.ПрочитатьСтроку(); Отчет = Новый ГенераторОтчетовBSL(); ВыражениеУбратьКавычки = Новый РегулярноеВыражение("(\s*[:\[][\S\s]+)"); @@ -33,13 +35,18 @@ // проверка EDT могла быть запущена по мультипроектам с одним файлом результата(напр. конфа + расширения) ГенераторыПутей = ИнициализироватьГенераторы(ПутьКРепозиторию, СписокПроектов); + + // найденные ошибки + ОшибкиПравил = Новый Массив; - Пока Строка <> Неопределено Цикл + НомерСтроки = 0; + Пока ПрочитаннаяСтрока <> Неопределено Цикл + НомерСтроки = НомерСтроки + 1; - СыроеЗамечание = РазобратьЗамечаниеВСтруктуру(Строка); + СыроеЗамечание = РазобратьЗамечаниеВСтруктуру(ПрочитаннаяСтрока); Если ДолженПропуститьСтроку(СыроеЗамечание) Тогда - Строка = Чтение.ПрочитатьСтроку(); + ПрочитаннаяСтрока = Чтение.ПрочитатьСтроку(); Продолжить; КонецЕсли; @@ -68,7 +75,7 @@ Если ПустаяСтрока(ОбъектЗамечания) Тогда Лог.Предупреждение("Не удалось найти объект 1С по исходникам - %1", МетаданныеЗамечания); - Строка = Чтение.ПрочитатьСтроку(); + ПрочитаннаяСтрока = Чтение.ПрочитатьСтроку(); Продолжить; КонецЕсли; @@ -93,13 +100,22 @@ Имя = ВыражениеУбратьКавычки.Заменить(СыроеЗамечание.Сообщение, ""); Имя = ВыражениеУбратьКавычки3.Заменить(Имя, ""); - Имя = СокрЛП(ВыражениеУбратьКавычки2.Заменить(Имя, ""));; + Имя = СокрЛП(ВыражениеУбратьКавычки2.Заменить(Имя, "")); + + НайденыСпецСимволы = ПроверитьНаличиеСимволовВСтроке(ПрочитаннаяСтрока, "@", Ложь); + Если НайденыСпецСимволы Тогда + ШаблонСообщенияОшибки = "Строка замечания содержит недопустимые символы (файл: %1, строка: %2, код: %3)"; + Лог.Ошибка(ШаблонСообщенияОшибки, Файл, НомерСтроки, КодПравила); + ОшибкиПравил.Добавить(ПолучитьСтруктуруОшибки(КодПравила, ПрочитаннаяСтрока)); + ПрочитаннаяСтрока = Чтение.ПрочитатьСтроку(); + Продолжить; + КонецЕсли; - Код = НайтиСоздатьПравило(ХранилищеПравил, КодПравила, Имя,СыроеЗамечание.Тип, СыроеЗамечание, МассивДобавлений); + Код = НайтиСоздатьПравило(ХранилищеПравил, КодПравила, Имя, СыроеЗамечание.Тип, СыроеЗамечание, МассивДобавлений); Замечание.code = Код; - Строка = Чтение.ПрочитатьСтроку(); + ПрочитаннаяСтрока = Чтение.ПрочитатьСтроку(); КонецЦикла; Чтение.Закрыть(); @@ -107,11 +123,44 @@ Если Добавлено Тогда ХранилищеПравил.Дополнить(МассивДобавлений); КонецЕсли; - + + ФайловыеОперации.СоздатьСтруктуруКаталоговФайла(ФайлРезультата); Отчет.ЗаписатьОтчет(ФайлРезультата); КонецПроцедуры +#КонецОбласти +#Область СлужебныйПрограммныйИнтерфейс + +// Возвращает объект +// +// Возвращаемое значение: +// ПарсерОшибок - парсер ошибок +// +Функция ПолучитьОбъект() Экспорт + Возврат ЭтотОбъект; +КонецФункции + + +// Получает коллекцию с ошибками правил +// +// Возвращаемое значение: +// Массив - ошибки правил +// +Функция ПолучитьОшибкиПравил() Экспорт + Возврат ОшибкиПравил; +КонецФункции + +// Проверяет наличие ошибок правил в коллекции +// +// Возвращаемое значение: +// Булево - Истина, если в коллекции присутствуют ошибки, иначе - Ложь +// +Функция ПроверитьНаличиеОшибокПравил() Экспорт + Возврат ЗначениеЗаполнено(ОшибкиПравил) И ОшибкиПравил.Количество() > 0; +КонецФункции + + #КонецОбласти #Область СлужебныеПроцедурыИФункции @@ -136,7 +185,11 @@ ИначеЕсли ПравилоОтсутствуетВХранилище Тогда - НовоеПравило = ХранилищеПравил.НовыйПравило(СтрокаПоиска, Имя, ТипыЗамечаний.Определить(Тип), КритичностьЗамечаний.Определить(Важность)); + ТипПравила = ТипыЗамечаний.Определить(Тип); + ВажностьПравила = КритичностьЗамечаний.Определить(Важность); + + НовоеПравило = ХранилищеПравил.НовыйПравило(СтрокаПоиска, Имя, ТипПравила, ВажностьПравила); + НовоеПравило.Code = "EDT" + "-" + (ХранилищеПравил.Количество() + МассивДобавлений.Количество() + 1); МассивДобавлений.Вставить(СтрокаПоиска, НовоеПравило); @@ -173,10 +226,10 @@ Если ЗначениеЗаполнено(Позиция) Тогда Попытка - НайденаяПозиция = Число(СтрЗаменить(Позиция, "строка ", "")); + НайденаяПозиция = Число(СтрЗаменить(Позиция, "строка ", "")); Исключение Попытка - НайденаяПозиция = Число(СтрЗаменить(Позиция, "line ", "")); + НайденаяПозиция = Число(СтрЗаменить(Позиция, "line ", "")); Исключение НайденаяПозиция = Неопределено; КонецПопытки; @@ -257,7 +310,61 @@ Возврат Пропуск; -КонецФункции; +КонецФункции + +// Готовит структуру для записи ошибки в коллекцию +// +// Параметры: +// Код - Строка - код правила +// СтрокаОшибки - Строка - исходная строка содержащая ошибку +// +// Возвращаемое значение: +// Структура: +// * КодПравила - Строка - код ошибки +// * ИсходнаяСтрока - Строка - строка с ошибкой +// +Функция ПолучитьСтруктуруОшибки(Код, СтрокаОшибки) + СтруктураОшибки = Новый Структура("КодПравила, ИсходнаяСтрока"); + СтруктураОшибки.КодПравила = Код; + СтруктураОшибки.ИсходнаяСтрока = СтрокаОшибки; + Возврат СтруктураОшибки; +КонецФункции + +// Выполняет поиск в строке указанных символов +// +// Параметры: +// ПроверяемаяСтрока - Строка - проверяемая строка +// СтрокаСпецСимволов - Строка - строка со спец. символами, например: "$@%" +// ИспользоватьРегулярноеВыражение - Булево - если "Истина" - поиск символов +// в строке будет выполнен с использованием функции "РегулярноеВыражение.НайтиСовпадения()". +// В ином случае поиск символов будет выполняться с использованием функции "СтрНайти()" +// +// Возвращаемое значение: +// Булево - Истина, если символы в строке были найдены, иначе - Ложь +// +Функция ПроверитьНаличиеСимволовВСтроке(ПроверяемаяСтрока, СтрокаСпецСимволов, ИспользоватьРегулярноеВыражение = Ложь) + Паттерн = ""; + СимволыНайденыВСтроке = Ложь; + Если ИспользоватьРегулярноеВыражение Тогда + Для Индекс = 1 По СтрДлина(СтрокаСпецСимволов) Цикл + СпецСимвол = Сред(СтрокаСпецСимволов, Индекс, 1); + Если Не ЗначениеЗаполнено(Паттерн) Тогда + Паттерн = СтрШаблон("\%1", СпецСимвол); + Продолжить; + КонецЕсли; + Паттерн = СтрШаблон("%1|\%2", Паттерн, СпецСимвол); + КонецЦикла; + ВыражениеНайтиНедопустимыеСимволы = Новый РегулярноеВыражение(СтрШаблон(".*(%1).*", Паттерн)); + КоллекцияГруппСовпадений = ВыражениеНайтиНедопустимыеСимволы.НайтиСовпадения(ПроверяемаяСтрока); + СимволыНайденыВСтроке = КоллекцияГруппСовпадений.Количество() > 0; + Иначе + СимволыНайденыВСтроке = СтрНайти(ПроверяемаяСтрока, СтрокаСпецСимволов) > 0; + КонецЕсли; + + Возврат СимволыНайденыВСтроке; +КонецФункции + + #КонецОбласти diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" index 5d57f5e..79ce62d 100644 --- "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" +++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" @@ -6,7 +6,7 @@ // ПутьКФайлу - Строка - Путь к файлу, который будет прочитан // ВСоответствие - Булево - От значения параметра зависит в какой тип будет происходить чтение // -// Возвращаемое значение: +// Возвращаемое значение: // Соответствие,Структура - Объект из json файла // Функция ПрочитатьОбъект(ПутьКФайлу, ВСоответствие = Истина) Экспорт @@ -28,12 +28,62 @@ ЗаписьJSON.ОткрытьФайл(ПутьКФайлу, "UTF-8", , Новый ПараметрыЗаписиJSON(, Символы.Таб)); ЗаписатьJSON(ЗаписьJSON, ОбъектЗаписи); ЗаписьJSON.Закрыть(); - КонецПроцедуры +// Создает объект JSON из строки JSON +// +// Параметры: +// СтрокаJSON - Строка - строка с json-содержимым +// ПолучитьБезопасно - Булево - Если "Истина", то +// +// Возвращаемое значение: +// Произвольный - объект JSON +// +Функция ПолучитьОбъектИзСтрокиJSON(СтрокаJSON, ПолучитьБезопасно = Ложь) Экспорт + + ОбъектJSON = Неопределено; + + ЧтениеJSON = Новый ЧтениеJSON(); + ЧтениеJSON.УстановитьСтроку(СтрокаJSON); + Попытка + ОбъектJSON = ПрочитатьJSON(ЧтениеJSON); + Исключение + Если Не ПолучитьБезопасно Тогда + ВызватьИсключение("Ошибка получения объекта JSON из строки " + ОписаниеОшибки()); + КонецЕсли; + КонецПопытки; + + ЧтениеJSON.Закрыть(); + Возврат ОбъектJSON; +КонецФункции + +// Выполняет построчное чтение файла по указанному пути и возвращает строку +// +// Параметры: +// ПутьКФайлу - Строка - путь до читаемого файла +// +// Возвращаемое значение: +// Строка - строка с содержимым файла +// +Функция ПрочитатьФайл(ПутьКФайлу) Экспорт + Если Не ПроверитьСуществованиеФайла(ПутьКФайлу) Тогда + ВызватьИсключение СтрШаблон("Файл по указанному пути не существует '%1'", ПутьКФайлу); + КонецЕсли; + + Результат = Новый Массив; + Текст = Новый ЧтениеТекста(ПутьКФайлу, КодировкаТекста.UTF8, , , Ложь); + ТС = Текст.ПрочитатьСтроку(); + Пока ТС <> Неопределено Цикл + Результат.Добавить(ТС); + ТС = Текст.ПрочитатьСтроку(); + КонецЦикла; + Текст.Закрыть(); + Возврат СтрСоединить(Результат, Символы.ПС); +КонецФункции + // Находит шаблон для отчета // -// Возвращаемое значение: +// Возвращаемое значение: // Строка - путь к файлу с шаблоном отчета // Функция РесурсОтчет() Экспорт @@ -44,7 +94,7 @@ // Находит шаблон замечания // -// Возвращаемое значение: +// Возвращаемое значение: // Строка - Путь к шаблону замечания // Функция РесурсЗамечание() Экспорт @@ -59,7 +109,7 @@ // Находит путь к каталогу с ресурсами // -// Возвращаемое значение: +// Возвращаемое значение: // Строка - путь к каталогу с ресурсами // Функция Ресурсы() Экспорт @@ -70,7 +120,7 @@ // Находит путь к каталогу исходных файлов программы // -// Возвращаемое значение: +// Возвращаемое значение: // Строка - Каталог исходных файлов программы // Функция КаталогИсходников() Экспорт @@ -79,7 +129,7 @@ // Находит путь к корневому каталогу программы // -// Возвращаемое значение: +// Возвращаемое значение: // Строка - Путь к корневому каталогу программы // Функция КаталогПрограммы() Экспорт @@ -88,30 +138,170 @@ // Находит внутренний файл правил // -// Возвращаемое значение: +// Параметры: +// ПутьФайлаПравил - Строка - имя файла правил (значение по-умолчанию: "custom-rules.json") +// +// Возвращаемое значение: // Строка - Путь к внутреннему файлу правил // -Функция ФайлПравилПрограммы() Экспорт - Возврат ОбъединитьПути(КаталогПрограммы(), "custom-rules.json"); +Функция ФайлПравилПрограммы(ПутьФайлаПравил = "custom-rules.json") Экспорт + Возврат ОбъединитьПути(КаталогПрограммы(), ПутьФайлаПравил); КонецФункции // Находит внутренний файл правил // // Параметры: // Путь - Строка - Путь к проекту -// Возвращаемое значение: +// +// Возвращаемое значение: // Строка - Имя - последняя часть пути // Функция ИмяФайлаИлиДиректории(Путь) Экспорт Возврат Новый Файл(Путь).ИмяБезРасширения; КонецФункции +// Проверяет существование файла +// +// Параметры: +// Путь - Строка - Путь к файлу +// +// Возвращаемое значение: +// Булево - Истина, если файл существует +// +Функция ПроверитьСуществованиеФайла(Путь) Экспорт + + Если Не ЗначениеЗаполнено(СокрЛП(Путь)) Тогда + Возврат Ложь; + КонецЕсли; + + Файл = Новый Файл(Путь); + ФайлСуществует = Файл.Существует() И Файл.ЭтоФайл(); + Файл = Неопределено; + + Возврат ФайлСуществует; + +КонецФункции + +// Проверяет существование каталога +// +// Параметры: +// Путь - Строка - Путь к каталогу +// +// Возвращаемое значение: +// Булево - Истина, если каталог существует +// +Функция ПроверитьСуществованиеКаталога(Путь) Экспорт + + Если Не ЗначениеЗаполнено(СокрЛП(Путь)) Тогда + Возврат Ложь; + КонецЕсли; + + Файл = Новый Файл(Путь); + КаталогСуществует = Файл.Существует() И Файл.ЭтоКаталог(); + Файл = Неопределено; + + Возврат КаталогСуществует; + +КонецФункции + +// Корректирует путь до конечного объекта (файла или каталога) +// * В качестве разделителей используется прямой слэш "/" +// +// Параметры: +// Путь - Строка - Путь к каталогу +// +// Возвращаемое значение: +// Строка - скорректированная строка пути к объекту (файлу или каталогу) +// +Функция ПолучитьКорректныйПутьФайла(Путь) Экспорт + ПутьСлеш = СтрЗаменить(Путь, "\", "/"); + ЧастиПути = СтрРазделить(ПутьСлеш, "/", Ложь); + КорректныйПутьФайла = ""; + Для Каждого ЧастьПути Из ЧастиПути Цикл + Если Не ЗначениеЗаполнено(СокрЛП(ЧастьПути)) Тогда + Продолжить; + КонецЕсли; + ЭтоДочернийКаталог = ЗначениеЗаполнено(СокрЛП(КорректныйПутьФайла)); + Если Не ЗначениеЗаполнено(КорректныйПутьФайла) И СтрНачинаетсяС(ПутьСлеш, "/") Тогда + КорректныйПутьФайла = "/" + ЧастьПути; + Продолжить; + КонецЕсли; + КорректныйПутьФайла = ?(ЭтоДочернийКаталог, КорректныйПутьФайла + "/" + ЧастьПути, ЧастьПути); + КонецЦикла; + Возврат КорректныйПутьФайла; +КонецФункции + +// Создает структуру каталогов для конечного файла +// +// Параметры: +// Путь - Строка - Путь к конечному файлу +// СоздатьПустойФайл - Булево - Если Истина - будет создан пустой файл +// +Процедура СоздатьСтруктуруКаталоговФайла(Путь, СоздатьПустойФайл = Ложь) Экспорт + + Если ПроверитьСуществованиеФайла(Путь) Тогда + Возврат; + КонецЕсли; + + Файл = Новый Файл(Путь); + ПутьФайла = Файл.Путь; + ЧастиПути = СтрРазделить(ПутьФайла, "/", Ложь); + ТекущийКаталог = ""; + Для Каждого ЧастьПути Из ЧастиПути Цикл + Если СтрНачинаетсяС(Путь, "/") И Не ЗначениеЗаполнено(ТекущийКаталог) Тогда + ТекущийКаталог = "/" + ЧастьПути; + Иначе + ТекущийКаталог = ?(ЗначениеЗаполнено(ТекущийКаталог), ТекущийКаталог + "/" + ЧастьПути, ЧастьПути); + КонецЕсли; + + Если Не ПроверитьСуществованиеКаталога(ТекущийКаталог) Тогда + СоздатьКаталог(ТекущийКаталог); + КонецЕсли; + КонецЦикла; + + Если СоздатьПустойФайл Тогда + СоздатьПустойФайл(Путь); + КонецЕсли; + +КонецПроцедуры + +// Получает имя файла по указанному пути +// +// Параметры: +// Путь - Строка - Путь к указанному файлу +// +// Возвращаемое значение: +// Строка - Имя файла +// +Функция ПолучитьИмяФайла(Путь) Экспорт + Файл = Новый Файл(Путь); + Возврат Файл.Имя; +КонецФункции + #КонецОбласти #Область СлужебныеПроцедурыИФункции +// Возврщает дирректорию ресурсов +// +// Возвращаемое значение: +// Строка - Имя дирректории +// Функция ДиректорияРесурсов() Возврат "Ресурсы"; КонецФункции -#КонецОбласти +// Создает пустой файл по указанному пути +// +// Параметры: +// Путь - путь создаваемого файла +// +Процедура СоздатьПустойФайл(Путь) + ЗаписьТекста = Новый ЗаписьТекста; + ЗаписьТекста.Открыть(Путь); + ЗаписьТекста.Записать(""); + ЗаписьТекста.Закрыть(); +КонецПроцедуры + + +#КонецОбласти \ No newline at end of file diff --git "a/tests/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" "b/tests/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" index 13adea5..9448d5d 100644 --- "a/tests/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" +++ "b/tests/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" @@ -64,7 +64,7 @@ ПутьКФайлу = МенеджерВременныхФайлов.СоздатьФайл("test.json"); - Объект = ФайловыеОперации.ПрочитатьОбъект(ФайловыеОперации.РесурсОтчет(), Истина); + Объект = ПрочитатьОбъект(ФайловыеОперации.РесурсОтчет(), Истина); Ожидаем.Что(ТипЗнч(Объект), "Типы не совпали").Равно(Тип("Соответствие")); ФайловыеОперации.ЗаписатьОбъект(ПутьКФайлу, Объект); From 5aa660bef6db77388bd110b8a9340b022acb376a Mon Sep 17 00:00:00 2001 From: Maximov Valery Date: Mon, 18 Mar 2024 13:36:39 +0300 Subject: [PATCH 4/6] =?UTF-8?q?=D0=A0=D0=B5=D0=BB=D0=B8=D0=B7=2024.03?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit + Новые правила и лог --- custom-rules.json | 300 ++++++++++++++++++ ...21\200\320\260\321\206\320\270\321\217.os" | 5 + ...20\266\320\265\320\275\320\270\321\217.os" | 2 +- ...20\265\321\200\321\201\320\270\321\217.os" | 4 +- 4 files changed, 308 insertions(+), 3 deletions(-) diff --git a/custom-rules.json b/custom-rules.json index 9c2167d..ed4bed3 100755 --- a/custom-rules.json +++ b/custom-rules.json @@ -1789,6 +1789,306 @@ "Severity": "MINOR", "Active": true, "EffortMinutes": 3 + }, + { + "Code": "EDT-180", + "InternalCode": "com.e1c.v8codestyle.bsl:variable-value-type", + "Name": "Переменная не имеет типа", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-181", + "InternalCode": "Несколько линий, исходящих из точки выбора варианта, входят в одну точку карты маршрута", + "Name": "Несколько линий, исходящих из точки выбора варианта, входят в одну точку карты маршрута", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-182", + "InternalCode": "com.e1c.v8codestyle.bsl:module-attachable-event-handler-name", + "Name": "Программно добавленное имя обработчика события должно соответствовать шаблону", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-183", + "InternalCode": "com.e1c.v8codestyle.md:common-module-name-client", + "Name": "Клиентский общий модуль должен оканчиваться на суффикс", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-184", + "InternalCode": "Некорректное значение свойства. Справочнику, имеющему предопределенные данные, нельзя назначить владельца!!", + "Name": "Некорректное значение свойства. Справочнику, имеющему предопределенные данные, нельзя назначить владельца!!", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-185", + "InternalCode": "com.e1c.v8codestyle.bsl:method-param-value-type", + "Name": "Параметр метода не имеет типа значения", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-186", + "InternalCode": "com.e1c.dt.check.form:form-invalid-item-id", + "Name": "Значение идентификатора элемента формы продублировано в другом элементе формы", + "Description": "Отсутствует", + "Type": "BUG", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-187", + "InternalCode": "Отсутствуют линии, входящие в точку карты маршрута", + "Name": "Отсутствуют линии, входящие в точку карты маршрута", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-188", + "InternalCode": "Текст метода имеет отличия от базового метода, что не допустимо в случае расширения", + "Name": "Текст метода имеет отличия от базового метода, что не допустимо в случае расширения", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-189", + "InternalCode": "com.e1c.v8codestyle.md:common-module-name-client-cached", + "Name": "Общий модуль должен именоваться с постфиксом КлиентПовтИсп", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-190", + "InternalCode": "com.e1c.v8codestyle.bsl:change-and-validate-instead-of-around", + "Name": "Рекомендуется использовать аннотацию &ИзменениеИКонтроль вместо &Вместо", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-191", + "InternalCode": "com.e1c.v8codestyle.bsl:extension-method-prefix", + "Name": "Имя метода должно содержать префикс", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-192", + "InternalCode": "com.e1c.v8codestyle.md:extension-md-object-prefix", + "Name": "Имя объекта должно содержать префикс", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-193", + "InternalCode": "com.e1c.v8codestyle.bsl:extension-variable-prefix", + "Name": "Переменная должна иметь префикс", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-194", + "InternalCode": "com.e1c.v8codestyle.bsl:invocation-parameter-type-intersect", + "Name": "Вызываемый тип выражения не пересекается с типом", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-195", + "InternalCode": "com.e1c.v8codestyle.bsl:typed-value-adding-to-untyped-collection", + "Name": "Добавление типизированного значения в не типизированную коллекцию", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-196", + "InternalCode": "com.e1c.v8codestyle.bsl:dynamic-access-method-not-found", + "Name": "Метод не найден в исходном объекте", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-197", + "InternalCode": "com.e1c.v8codestyle.bsl:property-return-type", + "Name": "Свойство не имеет типа возвращаемого значения", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-198", + "InternalCode": "com.e1c.v8codestyle.bsl:statement-type-change", + "Name": "Тип значения заменен на", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-199", + "InternalCode": "Не задано содержимое графы журнала", + "Name": "Не задано содержимое графы журнала", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-200", + "InternalCode": "Отличается сигнатура метода расширения от сигнатуры заимствованного метода. Количество параметров и их тип, тип и экспортируемость должны совпадать", + "Name": "Отличается сигнатура метода расширения от сигнатуры заимствованного метода. Количество параметров и их тип, тип и экспортируемость должны совпадать", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-201", + "InternalCode": "Оператор в функции должен возвращать определенное значение", + "Name": "Оператор в функции должен возвращать определенное значение", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-202", + "InternalCode": "Свойство недоступно для текущего режима совместимости", + "Name": "Свойство недоступно для текущего режима совместимости", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-203", + "InternalCode": "Не найден объект расширяемой конфигурации с внутренним идентификатором", + "Name": "Не найден объект расширяемой конфигурации с внутренним идентификатором", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-204", + "InternalCode": "Синтаксическая ошибка. Неверный ввод - ожидается\"", + "Name": "Синтаксическая ошибка. Неверный ввод - ожидается\"", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-205", + "InternalCode": "Расширяемый объект для объекта расширения с именем не найден.", + "Name": "Расширяемый объект для объекта расширения с именем не найден.", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-206", + "InternalCode": "com.e1c.v8codestyle.bsl:module-consecutive-blank-lines", + "Name": "Между строками расположено больше 1 пустых строк", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-207", + "InternalCode": "Инструкци препроцессора и не могут быть вложены друг в друга", + "Name": "Инструкци препроцессора и не могут быть вложены друг в друга", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-208", + "InternalCode": "Не правильно использовать аннотации для обработчиков событий формы", + "Name": "Не правильно использовать аннотации для обработчиков событий формы", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 + }, + { + "Code": "EDT-209", + "InternalCode": "Синтаксическая ошибка. Неверная лексема - ожидается\"", + "Name": "Синтаксическая ошибка. Неверная лексема - ожидается\"", + "Description": "Отсутствует", + "Type": "CODE_SMELL", + "Severity": "MINOR", + "Active": true, + "EffortMinutes": 3 } ] } \ No newline at end of file diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\206\320\270\321\217.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\206\320\270\321\217.os" index 257b586..7ad539b 100644 --- "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\206\320\270\321\217.os" +++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\206\320\270\321\217.os" @@ -88,8 +88,12 @@ // Функция ПодобратьМодуль(Генератор, Знач Объект) Экспорт + ЛогПоиска = Логирование.ПолучитьЛог("oscript.app.cf_info"); + ЛогПоиска.УстановитьУровень(УровниЛога.Ошибка); + Переопределение = ""; Шаблон = "%1.%2"; + ТипыМодулей = Новый Массив; ТипыМодулей.Добавить(СтрШаблон(Шаблон, Объект, "Модуль")); ТипыМодулей.Добавить(СтрШаблон(Шаблон, Объект, "МодульОбъекта")); @@ -110,6 +114,7 @@ КонецЦикла; + ЛогПоиска.УстановитьУровень(УровниЛога.Информация); Возврат Переопределение; КонецФункции diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" index 3e851fc..bb91f1d 100644 --- "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" +++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" @@ -145,7 +145,7 @@ // Функция Версия() Экспорт - Возврат "23.02"; + Возврат "24.03"; КонецФункции diff --git "a/tests/\320\222\320\265\321\200\321\201\320\270\321\217.os" "b/tests/\320\222\320\265\321\200\321\201\320\270\321\217.os" index c20d2fd..d054eeb 100644 --- "a/tests/\320\222\320\265\321\200\321\201\320\270\321\217.os" +++ "b/tests/\320\222\320\265\321\200\321\201\320\270\321\217.os" @@ -20,7 +20,7 @@ Процедура Тест_ПроверитьВерсию() Экспорт -// тест нужен чтобы лишний раз обратить внимание на изменение версии, и, возможно, стоит что-то доделать -Ожидаем.Что(ПараметрыПриложения.Версия()).Равно("23.02"); + // тест нужен чтобы лишний раз обратить внимание на изменение версии, и, возможно, стоит что-то доделать + Ожидаем.Что(ПараметрыПриложения.Версия()).Равно("24.03"); КонецПроцедуры From da1cc9644b5162b737cb0a505fa24538a4515873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B5=D0=B4=D0=B2=D0=B5=D0=B4=D0=B5=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=90=D0=BB=D0=B5=D0=BA?= =?UTF-8?q?=D1=81=D0=B0=D0=BD=D0=B4=D1=80=D0=BE=D0=B2=D0=B8=D1=87=20=28000?= =?UTF-8?q?095681=29?= Date: Tue, 19 Mar 2024 16:46:02 +0300 Subject: [PATCH 5/6] =?UTF-8?q?Update=20=D0=97=D0=B0=D0=B3=D1=80=D1=83?= =?UTF-8?q?=D0=B7=D1=87=D0=B8=D0=BA=D0=9F=D1=80=D0=B0=D0=B2=D0=B8=D0=BB.os?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\272\320\237\321\200\320\260\320\262\320\270\320\273.os" | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\227\320\260\320\263\321\200\321\203\320\267\321\207\320\270\320\272\320\237\321\200\320\260\320\262\320\270\320\273.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\227\320\260\320\263\321\200\321\203\320\267\321\207\320\270\320\272\320\237\321\200\320\260\320\262\320\270\320\273.os" index 63c68a5..c77f742 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\227\320\260\320\263\321\200\321\203\320\267\321\207\320\270\320\272\320\237\321\200\320\260\320\262\320\270\320\273.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\227\320\260\320\263\321\200\321\203\320\267\321\207\320\270\320\272\320\237\321\200\320\260\320\262\320\270\320\273.os" @@ -1,4 +1,3 @@ - #Использовать logos #Область ОписаниеПеременных @@ -630,9 +629,6 @@ Функция ПодготовитьHTTPСоединение() SSL = Неопределено; - Если СтруктураURI.Схема = "https" Тогда - SSL = Новый ЗащищенноеСоединениеOpenSSL; - КонецЕсли; Логин = ?(ЗначениеЗаполнено(СтруктураURI.Логин), СтруктураURI.Логин, Неопределено); Пароль = ?(ЗначениеЗаполнено(СтруктураURI.Пароль), СтруктураURI.Пароль, Неопределено); @@ -1064,4 +1060,4 @@ #КонецОбласти -Лог = ПараметрыПриложения.Лог(); \ No newline at end of file +Лог = ПараметрыПриложения.Лог(); From d344729782105a065e1b8d68f07e2c3fa34af1a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B5=D0=B4=D0=B2=D0=B5=D0=B4=D0=B5=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=90=D0=BB=D0=B5=D0=BA?= =?UTF-8?q?=D1=81=D0=B0=D0=BD=D0=B4=D1=80=D0=BE=D0=B2=D0=B8=D1=87=20=28000?= =?UTF-8?q?095681=29?= Date: Fri, 22 Mar 2024 08:42:10 +0300 Subject: [PATCH 6/6] =?UTF-8?q?=D0=9F=D0=BE=D0=BF=D0=B0=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20"=D0=BF=D1=83=D1=81=D1=82=D1=8B=D1=85"=20=D1=84?= =?UTF-8?q?=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2=20=D0=B2=20=D1=80=D0=B5=D0=B7?= =?UTF-8?q?=D1=83=D0=BB=D1=8C=D1=82=D0=B0=D1=82=D1=8B=20=D0=B8=20=D0=BB?= =?UTF-8?q?=D0=B8=D1=88=D0=BD=D0=B8=D0=B5=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- ...21\200\320\260\321\206\320\270\321\217.os" | 10 +++++++ ...21\200\320\260\321\206\320\270\320\270.os" | 19 +++++++++++++ ...20\265\321\200\321\201\320\270\321\217.os" | 4 +-- ...21\200\320\260\321\206\320\270\320\270.os" | 28 ++++++++++++++++++- 5 files changed, 60 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 25c57a4..162b526 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ out/* .rules/**/* .results/**/* .build/**/* -.report/**/* \ No newline at end of file +.report/**/* +*.orig diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\206\320\270\321\217.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\206\320\270\321\217.os" index 7ad539b..aaf18d4 100644 --- "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\206\320\270\321\217.os" +++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\206\320\270\321\217.os" @@ -1,5 +1,6 @@ #Использовать v8metadata-reader #Использовать fs +#Использовать logos #Область ОписаниеПеременных @@ -105,6 +106,9 @@ ТипыМодулей.Добавить(МодульОбычногоПриложенияСтрокой()); ТипыМодулей.Добавить(МодульСеансаСтрокой()); + ЛогПоиска = Логирование.ПолучитьЛог("oscript.app.cf_info"); + ЛогПоиска.УстановитьУровень(УровниЛога.Отключить); + Для Каждого ТипМодуля Из ТипыМодулей Цикл Если МожноИспользоватьВЗамечаниях(Генератор, ТипМодуля) Тогда @@ -114,6 +118,8 @@ КонецЦикла; + ЛогПоиска.УстановитьУровень(УровниЛога.Информация); + ЛогПоиска.УстановитьУровень(УровниЛога.Информация); Возврат Переопределение; @@ -151,6 +157,10 @@ Результат = Ложь; КонецЕсли; + Если Результат = Истина И ФайловыеОперации.ПустойФайл(Путь) Тогда + Результат = Ложь; + КонецЕсли; + Возврат Результат; КонецФункции diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" index 79ce62d..42814f0 100644 --- "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" +++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" @@ -1,5 +1,24 @@ #Область ПрограммныйИнтерфейс +// Проверяет, является ли файл пустым. +// Возвращает значение истину, если размер файла меньше или равен константе в байтах. +// В противном случае возвращается значение false. +// +// Параметры: +// ПутьКФайлу - Строка - Путь к файлу, который необходимо проверить. +// +// Возвращаемое значение: +// Булево - Признак пустоты файла +// +Функция ПустойФайл(ПутьКФайлу) Экспорт + + ГраницаПустотыВБайтах = 3; // Для BOM и переноса + Файл = Новый Файл(ПутьКФайлу); + Сообщить("" + Файл.Размер()); + Возврат Файл.Размер() <= ГраницаПустотыВБайтах; + +КонецФункции + // Читает json файл и преобразует его в объект // // Параметры: diff --git "a/tests/\320\222\320\265\321\200\321\201\320\270\321\217.os" "b/tests/\320\222\320\265\321\200\321\201\320\270\321\217.os" index d054eeb..7fb45ac 100644 --- "a/tests/\320\222\320\265\321\200\321\201\320\270\321\217.os" +++ "b/tests/\320\222\320\265\321\200\321\201\320\270\321\217.os" @@ -13,7 +13,7 @@ ВсеТесты = Новый Массив; ВсеТесты.Добавить("Тест_ПроверитьВерсию"); - + Возврат ВсеТесты; КонецФункции @@ -23,4 +23,4 @@ // тест нужен чтобы лишний раз обратить внимание на изменение версии, и, возможно, стоит что-то доделать Ожидаем.Что(ПараметрыПриложения.Версия()).Равно("24.03"); -КонецПроцедуры +КонецПроцедуры \ No newline at end of file diff --git "a/tests/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" "b/tests/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" index 9448d5d..09c65c4 100644 --- "a/tests/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" +++ "b/tests/\320\244\320\260\320\271\320\273\320\276\320\262\321\213\320\265\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.os" @@ -18,6 +18,7 @@ ВсеТесты = Новый Массив; ВсеТесты.Добавить("Тест_ПолучениеРесурсов"); + ВсеТесты.Добавить("Тест_РазмерФайла"); ВсеТесты.Добавить("Тест_СериализацияИДесериализация"); Возврат ВсеТесты; @@ -64,9 +65,34 @@ ПутьКФайлу = МенеджерВременныхФайлов.СоздатьФайл("test.json"); - Объект = ПрочитатьОбъект(ФайловыеОперации.РесурсОтчет(), Истина); + Объект = ФайловыеОперации.ПрочитатьОбъект(ФайловыеОперации.РесурсОтчет(), Истина); Ожидаем.Что(ТипЗнч(Объект), "Типы не совпали").Равно(Тип("Соответствие")); ФайловыеОперации.ЗаписатьОбъект(ПутьКФайлу, Объект); КонецПроцедуры + +Процедура Тест_РазмерФайла() Экспорт + + ПутьКФайлу = МенеджерВременныхФайлов.СоздатьФайл("module.bsl"); + + Пустота = ФайловыеОперации.ПустойФайл(ПутьКФайлу); + Ожидаем.Что(Пустота, "Ожидали что файл пустой").ЭтоИстина(); + + ПутьКФайлу = МенеджерВременныхФайлов.СоздатьФайл("module1.bsl"); + + Файл = Новый ЗаписьТекста(ПутьКФайлу); + Файл.ЗаписатьСтроку(Символы.НПП); + Файл.Закрыть(); + Пустота = ФайловыеОперации.ПустойФайл(ПутьКФайлу); + Ожидаем.Что(Пустота, "Ожидали что файл не пустой").ЭтоЛожь(); + + ПутьКФайлу = МенеджерВременныхФайлов.СоздатьФайл("module2.bsl"); + + Файл = Новый ЗаписьТекста(ПутьКФайлу); + Файл.ЗаписатьСтроку("//"); + Файл.Закрыть(); + Пустота = ФайловыеОперации.ПустойФайл(ПутьКФайлу); + Ожидаем.Что(Пустота, "Ожидали что файл не пустой").ЭтоЛожь(); + +КонецПроцедуры \ No newline at end of file