diff --git a/.gitignore b/.gitignore
index 73728ea..3bca798 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,5 @@
 /dist/
 /internal/config/version.txt
 .fleet
-.idea
\ No newline at end of file
+.idea
+.gigaide
\ No newline at end of file
diff --git a/pkg/build/build.go b/pkg/build/build.go
index ee1022d..69a8774 100644
--- a/pkg/build/build.go
+++ b/pkg/build/build.go
@@ -1,19 +1,29 @@
 /*
  * ALR - Any Linux Repository
+ * Любая Linux репозитория
  * Copyright (C) 2024 Евгений Храмов
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
+ * Это программное обеспечение свободно: вы можете распространять его и/или изменять
+ * на условиях GNU General Public License, опубликованной Free Software Foundation,
+ * либо версии 3 лицензии, либо (на ваш выбор) любой более поздней версии.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
+ * Это программное обеспечение распространяется в надежде, что оно будет полезным,
+ * но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ; даже без подразумеваемой гарантии
+ * КОММЕРЧЕСКОЙ ПРИГОДНОСТИ или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ. См.
+ * GNU General Public License для более подробной информации.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * Вы должны были получить копию GNU General Public License
+ * вместе с этой программой. Если нет, см. <http://www.gnu.org/licenses/>.
  */
 
 package build
@@ -32,6 +42,7 @@ import (
 	"strings"
 	"time"
 
+    // Импортируем пакеты для поддержки различных форматов пакетов (APK, DEB, RPM и ARCH).
 	_ "github.com/goreleaser/nfpm/v2/apk"
 	_ "github.com/goreleaser/nfpm/v2/arch"
 	_ "github.com/goreleaser/nfpm/v2/deb"
@@ -57,8 +68,8 @@ import (
 	"mvdan.cc/sh/v3/syntax"
 )
 
-// BuildPackage builds the script at the given path. It returns two slices. One contains the paths
-// to the built package(s), the other contains the names of the built package(s).
+// Функция BuildPackage выполняет сборку скрипта по указанному пути. Возвращает два среза.
+// Один содержит пути к собранным пакетам, другой - имена собранных пакетов.
 func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string, error) {
 	log := loggerctx.From(ctx)
 
@@ -72,9 +83,8 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
 		return nil, nil, err
 	}
 
-	// The first pass is just used to get variable values and runs before
-	// the script is displayed, so it's restricted so as to prevent malicious
-	// code from executing.
+    // Первый проход предназначен для получения значений переменных и выполняется
+    // до отображения скрипта, чтобы предотвратить выполнение вредоносного кода.
 	vars, err := executeFirstPass(ctx, info, fl, opts.Script)
 	if err != nil {
 		return nil, nil, err
@@ -82,8 +92,8 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
 
 	dirs := getDirs(ctx, vars, opts.Script)
 
-	// If opts.Clean isn't set and we find the package already built,
-	// just return it rather than rebuilding
+    // Если флаг opts.Clean не установлен, и пакет уже собран,
+    // возвращаем его, а не собираем заново.
 	if !opts.Clean {
 		builtPkgPath, ok, err := checkForBuiltPackage(opts.Manager, vars, getPkgFormat(opts.Manager), dirs.BaseDir)
 		if err != nil {
@@ -95,7 +105,7 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
 		}
 	}
 
-	// Ask the user if they'd like to see the build script
+    // Спрашиваем у пользователя, хочет ли он увидеть скрипт сборки.
 	err = cliutils.PromptViewScript(ctx, opts.Script, vars.Name, config.Config(ctx).PagerStyle, opts.Interactive)
 	if err != nil {
 		log.Fatal("Failed to prompt user to view build script").Err(err).Send()
@@ -103,161 +113,161 @@ func BuildPackage(ctx context.Context, opts types.BuildOpts) ([]string, []string
 
 	log.Info("Building package").Str("name", vars.Name).Str("version", vars.Version).Send()
 
-	// The second pass will be used to execute the actual code,
-	// so it's unrestricted. The script has already been displayed
-	// to the user by this point, so it should be safe
+    // Второй проход будет использоваться для выполнения реального кода,
+    // поэтому он не ограничен. Скрипт уже был показан
+    // пользователю к этому моменту, так что это должно быть безопасно.
 	dec, err := executeSecondPass(ctx, info, fl, dirs)
 	if err != nil {
 		return nil, nil, err
 	}
 
-	// Get the installed packages on the system
+	// Получаем список установленных пакетов в системе
 	installed, err := opts.Manager.ListInstalled(nil)
 	if err != nil {
 		return nil, nil, err
 	}
 
-	cont, err := performChecks(ctx, vars, opts.Interactive, installed)
+	cont, err := performChecks(ctx, vars, opts.Interactive, installed) // Выполняем различные проверки
 	if err != nil {
 		return nil, nil, err
 	} else if !cont {
-		os.Exit(1)
+		os.Exit(1) // Если проверки не пройдены, выходим из программы
 	}
 
-	// Prepare the directories for building
+    // Подготавливаем директории для сборки
 	err = prepareDirs(dirs)
 	if err != nil {
 		return nil, nil, err
 	}
 
-	buildDeps, err := installBuildDeps(ctx, vars, opts, installed)
+	buildDeps, err := installBuildDeps(ctx, vars, opts, installed) // Устанавливаем зависимости для сборки
 	if err != nil {
 		return nil, nil, err
 	}
 
-	err = installOptDeps(ctx, vars, opts, installed)
+	err = installOptDeps(ctx, vars, opts, installed) // Устанавливаем опциональные зависимости
 	if err != nil {
 		return nil, nil, err
 	}
 
-	builtPaths, builtNames, repoDeps, err := buildALRDeps(ctx, opts, vars)
+	builtPaths, builtNames, repoDeps, err := buildALRDeps(ctx, opts, vars) // Собираем зависимости
 	if err != nil {
 		return nil, nil, err
 	}
 
-	log.Info("Downloading sources").Send()
+	log.Info("Downloading sources").Send() // Записываем в лог загрузку источников
 
-	err = getSources(ctx, dirs, vars)
+	err = getSources(ctx, dirs, vars) // Загружаем исходники
 	if err != nil {
 		return nil, nil, err
 	}
 
-	err = executeFunctions(ctx, dec, dirs, vars)
+	err = executeFunctions(ctx, dec, dirs, vars) // Выполняем специальные функции
 	if err != nil {
 		return nil, nil, err
 	}
 
-	log.Info("Building package metadata").Str("name", vars.Name).Send()
+	log.Info("Building package metadata").Str("name", vars.Name).Send() // Логгируем сборку метаданных пакета
 
-	pkgFormat := getPkgFormat(opts.Manager)
+	pkgFormat := getPkgFormat(opts.Manager) // Получаем формат пакета
 
-	pkgInfo, err := buildPkgMetadata(vars, dirs, pkgFormat, append(repoDeps, builtNames...))
+	pkgInfo, err := buildPkgMetadata(vars, dirs, pkgFormat, append(repoDeps, builtNames...)) // Собираем метаданные пакета
 	if err != nil {
 		return nil, nil, err
 	}
 
-	packager, err := nfpm.Get(pkgFormat)
+	packager, err := nfpm.Get(pkgFormat) // Получаем упаковщик для формата пакета
 	if err != nil {
 		return nil, nil, err
 	}
 
-	pkgName := packager.ConventionalFileName(pkgInfo)
-	pkgPath := filepath.Join(dirs.BaseDir, pkgName)
+	pkgName := packager.ConventionalFileName(pkgInfo) // Получаем имя файла пакета
+	pkgPath := filepath.Join(dirs.BaseDir, pkgName) // Определяем путь к пакету
 
-	pkgFile, err := os.Create(pkgPath)
+	pkgFile, err := os.Create(pkgPath) // Создаём файл пакета
 	if err != nil {
 		return nil, nil, err
 	}
 
-	log.Info("Compressing package").Str("name", pkgName).Send()
+	log.Info("Compressing package").Str("name", pkgName).Send() // Логгируем сжатие пакета
 
-	err = packager.Package(pkgInfo, pkgFile)
+	err = packager.Package(pkgInfo, pkgFile) // Упаковываем пакет
 	if err != nil {
 		return nil, nil, err
 	}
 
-	err = removeBuildDeps(ctx, buildDeps, opts)
+	err = removeBuildDeps(ctx, buildDeps, opts) // Удаляем зависимости для сборки
 	if err != nil {
 		return nil, nil, err
 	}
 
-	// Add the path and name of the package we just built to the
-	// appropriate slices
+    // Добавляем путь и имя только что собранного пакета в
+    // соответствующие срезы
 	pkgPaths := append(builtPaths, pkgPath)
 	pkgNames := append(builtNames, vars.Name)
 
-	// Remove any duplicates from the pkgPaths and pkgNames.
-	// Duplicates can be introduced if several of the dependencies
-	// depend on the same packages.
+    // Удаляем дубликаты из pkgPaths и pkgNames.
+    // Дубликаты могут появиться, если несколько зависимостей
+    // зависят от одних и тех же пакетов.
 	pkgPaths = removeDuplicates(pkgPaths)
 	pkgNames = removeDuplicates(pkgNames)
 
-	return pkgPaths, pkgNames, nil
+	return pkgPaths, pkgNames, nil // Возвращаем пути и имена пакетов
 }
 
-// parseScript parses the build script using the built-in bash implementation
+// Функция parseScript анализирует скрипт сборки с использованием встроенной реализации bash
 func parseScript(info *distro.OSRelease, script string) (*syntax.File, error) {
-	fl, err := os.Open(script)
+	fl, err := os.Open(script) // Открываем файл скрипта
 	if err != nil {
 		return nil, err
 	}
-	defer fl.Close()
+	defer fl.Close() // Закрываем файл после выполнения
 
-	file, err := syntax.NewParser().Parse(fl, "alr.sh")
+	file, err := syntax.NewParser().Parse(fl, "alr.sh") // Парсим скрипт с помощью синтаксического анализатора
 	if err != nil {
 		return nil, err
 	}
 
-	return file, nil
+	return file, nil // Возвращаем синтаксическое дерево
 }
 
-// executeFirstPass executes the parsed script in a restricted environment
-// to extract the build variables without executing any actual code.
+// Функция executeFirstPass выполняет парсированный скрипт в ограниченной среде,
+// чтобы извлечь переменные сборки без выполнения реального кода.
 func executeFirstPass(ctx context.Context, info *distro.OSRelease, fl *syntax.File, script string) (*types.BuildVars, error) {
-	scriptDir := filepath.Dir(script)
-	env := createBuildEnvVars(info, types.Directories{ScriptDir: scriptDir})
+	scriptDir := filepath.Dir(script) // Получаем директорию скрипта
+	env := createBuildEnvVars(info, types.Directories{ScriptDir: scriptDir}) // Создаём переменные окружения для сборки
 
 	runner, err := interp.New(
-		interp.Env(expand.ListEnviron(env...)),
-		interp.StdIO(os.Stdin, os.Stdout, os.Stderr),
-		interp.ExecHandler(helpers.Restricted.ExecHandler(handlers.NopExec)),
-		interp.ReadDirHandler(handlers.RestrictedReadDir(scriptDir)),
-		interp.StatHandler(handlers.RestrictedStat(scriptDir)),
-		interp.OpenHandler(handlers.RestrictedOpen(scriptDir)),
+		interp.Env(expand.ListEnviron(env...)), // Устанавливаем окружение
+		interp.StdIO(os.Stdin, os.Stdout, os.Stderr), // Устанавливаем стандартный ввод-вывод
+		interp.ExecHandler(helpers.Restricted.ExecHandler(handlers.NopExec)), // Ограничиваем выполнение
+		interp.ReadDirHandler(handlers.RestrictedReadDir(scriptDir)), // Ограничиваем чтение директорий
+		interp.StatHandler(handlers.RestrictedStat(scriptDir)), // Ограничиваем доступ к статистике файлов
+		interp.OpenHandler(handlers.RestrictedOpen(scriptDir)), // Ограничиваем открытие файлов
 	)
 	if err != nil {
 		return nil, err
 	}
 
-	err = runner.Run(ctx, fl)
+	err = runner.Run(ctx, fl) // Запускаем скрипт
 	if err != nil {
 		return nil, err
 	}
 
-	dec := decoder.New(info, runner)
+	dec := decoder.New(info, runner) // Создаём новый декодер
 
 	var vars types.BuildVars
-	err = dec.DecodeVars(&vars)
+	err = dec.DecodeVars(&vars) // Декодируем переменные
 	if err != nil {
 		return nil, err
 	}
 
-	return &vars, nil
+	return &vars, nil // Возвращаем переменные сборки
 }
 
-// getDirs returns the appropriate directories for the script
+// Функция getDirs возвращает соответствующие директории для скрипта
 func getDirs(ctx context.Context, vars *types.BuildVars, script string) types.Directories {
-	baseDir := filepath.Join(config.GetPaths(ctx).PkgsDir, vars.Name)
+	baseDir := filepath.Join(config.GetPaths(ctx).PkgsDir, vars.Name) // Определяем базовую директорию
 	return types.Directories{
 		BaseDir:   baseDir,
 		SrcDir:    filepath.Join(baseDir, "src"),
@@ -266,46 +276,46 @@ func getDirs(ctx context.Context, vars *types.BuildVars, script string) types.Di
 	}
 }
 
-// executeSecondPass executes the build script for the second time, this time without any restrictions.
-// It returns a decoder that can be used to retrieve functions and variables from the script.
+// Функция executeSecondPass выполняет скрипт сборки второй раз без каких-либо ограничений. Возвращается декодер,
+// который может быть использован для получения функций и переменных из скрипта.
 func executeSecondPass(ctx context.Context, info *distro.OSRelease, fl *syntax.File, dirs types.Directories) (*decoder.Decoder, error) {
-	env := createBuildEnvVars(info, dirs)
+	env := createBuildEnvVars(info, dirs) // Создаём переменные окружения для сборки
 
-	fakeroot := handlers.FakerootExecHandler(2 * time.Second)
+	fakeroot := handlers.FakerootExecHandler(2 * time.Second) // Настраиваем "fakeroot" для выполнения
 	runner, err := interp.New(
-		interp.Env(expand.ListEnviron(env...)),
-		interp.StdIO(os.Stdin, os.Stdout, os.Stderr),
-		interp.ExecHandler(helpers.Helpers.ExecHandler(fakeroot)),
+		interp.Env(expand.ListEnviron(env...)), // Устанавливаем окружение
+		interp.StdIO(os.Stdin, os.Stdout, os.Stderr), // Устанавливаем стандартный ввод-вывод
+		interp.ExecHandler(helpers.Helpers.ExecHandler(fakeroot)), // Обрабатываем выполнение через fakeroot
 	)
 	if err != nil {
 		return nil, err
 	}
 
-	err = runner.Run(ctx, fl)
+	err = runner.Run(ctx, fl) // Запускаем скрипт
 	if err != nil {
 		return nil, err
 	}
 
-	return decoder.New(info, runner), nil
+	return decoder.New(info, runner), nil // Возвращаем новый декодер
 }
 
-// prepareDirs prepares the directories for building.
+// Функция prepareDirs подготавливает директории для сборки.
 func prepareDirs(dirs types.Directories) error {
-	err := os.RemoveAll(dirs.BaseDir)
+	err := os.RemoveAll(dirs.BaseDir) // Удаляем базовую директорию, если она существует
 	if err != nil {
 		return err
 	}
-	err = os.MkdirAll(dirs.SrcDir, 0o755)
+	err = os.MkdirAll(dirs.SrcDir, 0o755) // Создаем директорию для источников
 	if err != nil {
 		return err
 	}
-	return os.MkdirAll(dirs.PkgDir, 0o755)
+	return os.MkdirAll(dirs.PkgDir, 0o755) // Создаем директорию для пакетов
 }
 
-// performChecks checks various things on the system to ensure that the package can be installed.
+// Функция performChecks проверяет различные аспекты в системе, чтобы убедиться, что пакет может быть установлен.
 func performChecks(ctx context.Context, vars *types.BuildVars, interactive bool, installed map[string]string) (bool, error) {
 	log := loggerctx.From(ctx)
-	if !cpu.IsCompatibleWith(cpu.Arch(), vars.Architectures) {
+	if !cpu.IsCompatibleWith(cpu.Arch(), vars.Architectures) { // Проверяем совместимость архитектуры
 		cont, err := cliutils.YesNoPrompt(ctx, "Your system's CPU architecture doesn't match this package. Do you want to build anyway?", interactive, true)
 		if err != nil {
 			return false, err
@@ -316,7 +326,7 @@ func performChecks(ctx context.Context, vars *types.BuildVars, interactive bool,
 		}
 	}
 
-	if instVer, ok := installed[vars.Name]; ok {
+	if instVer, ok := installed[vars.Name]; ok { // Если пакет уже установлен, выводим предупреждение
 		log.Warn("This package is already installed").
 			Str("name", vars.Name).
 			Str("version", instVer).
@@ -326,33 +336,33 @@ func performChecks(ctx context.Context, vars *types.BuildVars, interactive bool,
 	return true, nil
 }
 
-// installBuildDeps installs any build dependencies that aren't already installed and returns
-// a slice containing the names of all the packages it installed.
+// Функция installBuildDeps устанавливает все зависимости сборки, которые еще не установлены, и возвращает
+// срез, содержащий имена всех установленных пакетов.
 func installBuildDeps(ctx context.Context, vars *types.BuildVars, opts types.BuildOpts, installed map[string]string) ([]string, error) {
 	log := loggerctx.From(ctx)
 	var buildDeps []string
 	if len(vars.BuildDepends) > 0 {
-		found, notFound, err := repos.FindPkgs(ctx, vars.BuildDepends)
+		found, notFound, err := repos.FindPkgs(ctx, vars.BuildDepends) // Находим пакеты-зависимости
 		if err != nil {
 			return nil, err
 		}
 
-		found = removeAlreadyInstalled(found, installed)
+		found = removeAlreadyInstalled(found, installed) // Убираем уже установленные зависимости
 
-		log.Info("Installing build dependencies").Send()
+		log.Info("Installing build dependencies").Send() // Логгируем установку зависимостей
 
-		flattened := cliutils.FlattenPkgs(ctx, found, "install", opts.Interactive)
+		flattened := cliutils.FlattenPkgs(ctx, found, "install", opts.Interactive) // Уплощаем список зависимостей
 		buildDeps = packageNames(flattened)
-		InstallPkgs(ctx, flattened, notFound, opts)
+		InstallPkgs(ctx, flattened, notFound, opts) // Устанавливаем пакеты
 	}
 	return buildDeps, nil
 }
 
-// installOptDeps asks the user which, if any, optional dependencies they want to install.
-// If the user chooses to install any optional dependencies, it performs the installation.
+// Функция installOptDeps спрашивает у пользователя, какие, если таковые имеются, опциональные зависимости он хочет установить.
+// Если пользователь решает установить какие-либо опциональные зависимости, выполняется их установка.
 func installOptDeps(ctx context.Context, vars *types.BuildVars, opts types.BuildOpts, installed map[string]string) error {
 	if len(vars.OptDepends) > 0 {
-		optDeps, err := cliutils.ChooseOptDepends(ctx, vars.OptDepends, "install", opts.Interactive)
+		optDeps, err := cliutils.ChooseOptDepends(ctx, vars.OptDepends, "install", opts.Interactive) // Пользователя просят выбрать опциональные зависимости
 		if err != nil {
 			return err
 		}
@@ -361,63 +371,63 @@ func installOptDeps(ctx context.Context, vars *types.BuildVars, opts types.Build
 			return nil
 		}
 
-		found, notFound, err := repos.FindPkgs(ctx, optDeps)
+		found, notFound, err := repos.FindPkgs(ctx, optDeps) // Находим опциональные зависимости
 		if err != nil {
 			return err
 		}
 
-		found = removeAlreadyInstalled(found, installed)
+		found = removeAlreadyInstalled(found, installed) // Убираем уже установленные зависимости
 		flattened := cliutils.FlattenPkgs(ctx, found, "install", opts.Interactive)
-		InstallPkgs(ctx, flattened, notFound, opts)
+		InstallPkgs(ctx, flattened, notFound, opts) // Устанавливаем выбранные пакеты
 	}
 	return nil
 }
 
-// buildALRDeps builds all the ALR dependencies of the package. It returns the paths and names
-// of the packages it built, as well as all the dependencies it didn't find in the ALR repo so
-// they can be installed from the system repos.
+// Функция buildALRDeps собирает все ALR зависимости пакета. Возвращает пути и имена
+// пакетов, которые она собрала, а также все зависимости, которые не были найдены в ALR репозитории,
+// чтобы они могли быть установлены из системных репозиториев.
 func buildALRDeps(ctx context.Context, opts types.BuildOpts, vars *types.BuildVars) (builtPaths, builtNames, repoDeps []string, err error) {
 	log := loggerctx.From(ctx)
 	if len(vars.Depends) > 0 {
 		log.Info("Installing dependencies").Send()
 
-		found, notFound, err := repos.FindPkgs(ctx, vars.Depends)
+		found, notFound, err := repos.FindPkgs(ctx, vars.Depends) // Поиск зависимостей
 		if err != nil {
 			return nil, nil, nil, err
 		}
 		repoDeps = notFound
 
-		// If there are multiple options for some packages, flatten them all into a single slice
+        // Если для некоторых пакетов есть несколько опций, упрощаем их все в один срез
 		pkgs := cliutils.FlattenPkgs(ctx, found, "install", opts.Interactive)
 		scripts := GetScriptPaths(ctx, pkgs)
 		for _, script := range scripts {
 			newOpts := opts
 			newOpts.Script = script
 
-			// Build the dependency
+            // Собираем зависимости
 			pkgPaths, pkgNames, err := BuildPackage(ctx, newOpts)
 			if err != nil {
 				return nil, nil, nil, err
 			}
 
-			// Append the paths of all the built packages to builtPaths
+            // Добавляем пути всех собранных пакетов в builtPaths
 			builtPaths = append(builtPaths, pkgPaths...)
-			// Append the names of all the built packages to builtNames
+            // Добавляем пути всех собранных пакетов в builtPaths
 			builtNames = append(builtNames, pkgNames...)
-			// Append the name of the current package to builtNames
+            // Добавляем имя текущего пакета в builtNames
 			builtNames = append(builtNames, filepath.Base(filepath.Dir(script)))
 		}
 	}
 
-	// Remove any potential duplicates, which can be introduced if
-	// several of the dependencies depend on the same packages.
+    // Удаляем возможные дубликаты, которые могут быть введены, если
+    // несколько зависимостей зависят от одних и тех же пакетов.
 	repoDeps = removeDuplicates(repoDeps)
 	builtPaths = removeDuplicates(builtPaths)
 	builtNames = removeDuplicates(builtNames)
 	return builtPaths, builtNames, repoDeps, nil
 }
 
-// executeFunctions executes the special ALR functions, such as version(), prepare(), etc.
+// Функция executeFunctions выполняет специальные функции ALR, такие как version(), prepare() и т.д.
 func executeFunctions(ctx context.Context, dec *decoder.Decoder, dirs types.Directories, vars *types.BuildVars) (err error) {
 	log := loggerctx.From(ctx)
 	version, ok := dec.GetFunc("version")
@@ -465,22 +475,34 @@ func executeFunctions(ctx context.Context, dec *decoder.Decoder, dirs types.Dire
 		}
 	}
 
-	packageFn, ok := dec.GetFunc("package")
-	if ok {
-		log.Info("Executing package()").Send()
+    // Выполнение всех функций, начинающихся с package_
+    for {
+        packageFn, ok := dec.GetFunc("package")
+        if ok {
+            log.Info("Executing package()").Send()
+            err = packageFn(ctx, interp.Dir(dirs.SrcDir))
+            if err != nil {
+                return err
+            }
+        }
 
-		err = packageFn(ctx, interp.Dir(dirs.SrcDir))
-		if err != nil {
-			return err
-		}
-	} else {
-		log.Fatal("The package() function is required").Send()
-	}
+        // Проверка на наличие дополнительных функций package_*
+        packageFuncName := "package_"
+        if packageFunc, ok := dec.GetFunc(packageFuncName); ok {
+            log.Info("Executing " + packageFuncName).Send()
+            err = packageFunc(ctx, interp.Dir(dirs.SrcDir))
+            if err != nil {
+                return err
+            }
+        } else {
+            break // Если больше нет функций package_*, выходим из цикла
+        }
+    }
 
 	return nil
 }
 
-// buildPkgMetadata builds the metadata for the package that's going to be built.
+// Функция buildPkgMetadata создает метаданные для пакета, который будет собран.
 func buildPkgMetadata(vars *types.BuildVars, dirs types.Directories, pkgFormat string, deps []string) (*nfpm.Info, error) {
 	pkgInfo := &nfpm.Info{
 		Name:        vars.Name,
@@ -501,7 +523,7 @@ func buildPkgMetadata(vars *types.BuildVars, dirs types.Directories, pkgFormat s
 	}
 
 	if pkgFormat == "apk" {
-		// Alpine refuses to install packages that provide themselves, so remove any such provides
+        // Alpine отказывается устанавливать пакеты, которые предоставляют сами себя, поэтому удаляем такие элементы
 		pkgInfo.Overridables.Provides = slices.DeleteFunc(pkgInfo.Overridables.Provides, func(s string) bool {
 			return s == pkgInfo.Name
 		})
@@ -526,8 +548,8 @@ func buildPkgMetadata(vars *types.BuildVars, dirs types.Directories, pkgFormat s
 	return pkgInfo, nil
 }
 
-// buildContents builds the contents section of the package, which contains the files
-// that will be placed into the final package.
+// Функция buildContents создает секцию содержимого пакета, которая содержит файлы,
+// которые будут включены в конечный пакет.
 func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Content, error) {
 	contents := []*files.Content{}
 	err := filepath.Walk(dirs.PkgDir, func(path string, fi os.FileInfo, err error) error {
@@ -539,7 +561,7 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont
 				return err
 			}
 
-			// If the directory is empty, skip it
+            // Если директория пустая, пропускаем её
 			_, err = f.Readdirnames(1)
 			if err != io.EOF {
 				return nil
@@ -556,13 +578,13 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont
 
 			return f.Close()
 		}
-
+        // Если файл является символической ссылкой, прорабатываем это
 		if fi.Mode()&os.ModeSymlink != 0 {
 			link, err := os.Readlink(path)
 			if err != nil {
 				return err
 			}
-			// Remove pkgdir from the symlink's path
+            // Удаляем pkgdir из пути символической ссылки
 			link = strings.TrimPrefix(link, dirs.PkgDir)
 
 			contents = append(contents, &files.Content{
@@ -577,7 +599,7 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont
 
 			return nil
 		}
-
+        // Обрабатываем обычные файлы
 		fileContent := &files.Content{
 			Source:      path,
 			Destination: trimmed,
@@ -588,7 +610,7 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont
 			},
 		}
 
-		// If the file is supposed to be backed up, set its type to config|noreplace
+        // Если файл должен быть сохранен, установите его тип как config|noreplace
 		if slices.Contains(vars.Backup, trimmed) {
 			fileContent.Type = "config|noreplace"
 		}
@@ -600,8 +622,8 @@ func buildContents(vars *types.BuildVars, dirs types.Directories) ([]*files.Cont
 	return contents, err
 }
 
-// removeBuildDeps asks the user if they'd like to remove the build dependencies that were
-// installed by installBuildDeps. If so, it uses the package manager to do that.
+// Функция removeBuildDeps спрашивает у пользователя, хочет ли он удалить зависимости,
+// установленные для сборки. Если да, использует менеджер пакетов для их удаления.
 func removeBuildDeps(ctx context.Context, buildDeps []string, opts types.BuildOpts) error {
 	if len(buildDeps) > 0 {
 		remove, err := cliutils.YesNoPrompt(ctx, "Would you like to remove the build dependencies?", opts.Interactive, false)
@@ -625,8 +647,8 @@ func removeBuildDeps(ctx context.Context, buildDeps []string, opts types.BuildOp
 	return nil
 }
 
-// checkForBuiltPackage tries to detect a previously-built package and returns its path
-// and true if it finds one. If it doesn't find it, it returns "", false, nil.
+// Функция checkForBuiltPackage пытается обнаружить ранее собранный пакет и вернуть его путь
+// и true, если нашла. Если нет, возвратит "", false, nil.
 func checkForBuiltPackage(mgr manager.Manager, vars *types.BuildVars, pkgFormat, baseDir string) (string, bool, error) {
 	filename, err := pkgFileName(vars, pkgFormat)
 	if err != nil {
@@ -643,8 +665,8 @@ func checkForBuiltPackage(mgr manager.Manager, vars *types.BuildVars, pkgFormat,
 	return pkgPath, true, nil
 }
 
-// pkgFileName returns the filename of the package if it were to be built.
-// This is used to check if the package has already been built.
+// Функция pkgFileName возвращает имя файла пакета, если оно было бы создано.
+// Это используется для проверки, был ли пакет уже собран.
 func pkgFileName(vars *types.BuildVars, pkgFormat string) (string, error) {
 	pkgInfo := &nfpm.Info{
 		Name:    vars.Name,
@@ -662,8 +684,8 @@ func pkgFileName(vars *types.BuildVars, pkgFormat string) (string, error) {
 	return packager.ConventionalFileName(pkgInfo), nil
 }
 
-// getPkgFormat returns the package format of the package manager,
-// or ALR_PKG_FORMAT if that's set.
+// Функция getPkgFormat возвращает формат пакета из менеджера пакетов,
+// или ALR_PKG_FORMAT, если он установлен.
 func getPkgFormat(mgr manager.Manager) string {
 	pkgFormat := mgr.Format()
 	if format, ok := os.LookupEnv("ALR_PKG_FORMAT"); ok {
@@ -672,8 +694,8 @@ func getPkgFormat(mgr manager.Manager) string {
 	return pkgFormat
 }
 
-// createBuildEnvVars creates the environment variables that will be set in the
-// build script when it's executed.
+// Функция createBuildEnvVars создает переменные окружения, которые будут установлены
+// в скрипте сборки при его выполнении.
 func createBuildEnvVars(info *distro.OSRelease, dirs types.Directories) []string {
 	env := os.Environ()
 
@@ -703,7 +725,7 @@ func createBuildEnvVars(info *distro.OSRelease, dirs types.Directories) []string
 	return env
 }
 
-// getSources downloads the sources from the script.
+// Функция getSources загружает исходники скрипта.
 func getSources(ctx context.Context, dirs types.Directories, bv *types.BuildVars) error {
 	log := loggerctx.From(ctx)
 	if len(bv.Sources) != len(bv.Checksums) {
@@ -720,9 +742,9 @@ func getSources(ctx context.Context, dirs types.Directories, bv *types.BuildVars
 		}
 
 		if !strings.EqualFold(bv.Checksums[i], "SKIP") {
-			// If the checksum contains a colon, use the part before the colon
-			// as the algorithm and the part after as the actual checksum.
-			// Otherwise, use the default sha256 with the whole string as the checksum.
+            // Если контрольная сумма содержит двоеточие, используйте часть до двоеточия
+            // как алгоритм, а часть после как фактическую контрольную сумму.
+            // В противном случае используйте sha256 по умолчанию с целой строкой как контрольной суммой.
 			algo, hashData, ok := strings.Cut(bv.Checksums[i], ":")
 			if ok {
 				checksum, err := hex.DecodeString(hashData)
@@ -749,7 +771,7 @@ func getSources(ctx context.Context, dirs types.Directories, bv *types.BuildVars
 	return nil
 }
 
-// setScripts adds any hook scripts to the package metadata.
+// Функция setScripts добавляет скрипты-перехватчики к метаданным пакета.
 func setScripts(vars *types.BuildVars, info *nfpm.Info, scriptDir string) {
 	if vars.Scripts.PreInstall != "" {
 		info.Scripts.PreInstall = filepath.Join(scriptDir, vars.Scripts.PreInstall)
@@ -786,8 +808,8 @@ func setScripts(vars *types.BuildVars, info *nfpm.Info, scriptDir string) {
 	}
 }
 
-// setVersion changes the version variable in the script runner.
-// It's used to set the version to the output of the version() function.
+// Функция setVersion изменяет переменную версии в скрипте runner.
+// Она используется для установки версии на вывод функции version().
 func setVersion(ctx context.Context, r *interp.Runner, to string) error {
 	fl, err := syntax.NewParser().Parse(strings.NewReader("version='"+to+"'"), "")
 	if err != nil {
@@ -796,7 +818,7 @@ func setVersion(ctx context.Context, r *interp.Runner, to string) error {
 	return r.Run(ctx, fl)
 }
 
-// removeAlreadyInstalled returns a map without any dependencies that are already installed
+// Функция removeAlreadyInstalled возвращает карту без каких-либо зависимостей, которые уже установлены.
 func removeAlreadyInstalled(found map[string][]db.Package, installed map[string]string) map[string][]db.Package {
 	filteredPackages := make(map[string][]db.Package)
 
@@ -813,7 +835,7 @@ func removeAlreadyInstalled(found map[string][]db.Package, installed map[string]
 	return filteredPackages
 }
 
-// packageNames returns the names of all the given packages
+// Функция packageNames возвращает имена всех предоставленных пакетов.
 func packageNames(pkgs []db.Package) []string {
 	names := make([]string, len(pkgs))
 	for i, p := range pkgs {
@@ -822,7 +844,7 @@ func packageNames(pkgs []db.Package) []string {
 	return names
 }
 
-// removeDuplicates removes any duplicates from the given slice
+// Функция removeDuplicates убирает любые дубликаты из предоставленного среза.
 func removeDuplicates(slice []string) []string {
 	seen := map[string]struct{}{}
 	result := []string{}
diff --git a/pkg/build/install.go b/pkg/build/install.go
index 9d99cc1..19ee98f 100644
--- a/pkg/build/install.go
+++ b/pkg/build/install.go
@@ -1,19 +1,30 @@
 /*
  * ALR - Any Linux Repository
+ * ALR - Любой Linux Репозиторий
  * Copyright (C) 2024 Евгений Храмов
  *
  * This program is free software: you can redistribute it and/or modify
+ * Это программное обеспечение является свободным: вы можете распространять его и/или изменять
  * it under the terms of the GNU General Public License as published by
+ * на условиях GNU General Public License, опубликованной
  * the Free Software Foundation, either version 3 of the License, or
+ * Free Software Foundation, либо версии 3 лицензии, либо
  * (at your option) any later version.
+ * (по вашему усмотрению) любой более поздней версии.
  *
  * This program is distributed in the hope that it will be useful,
+ * Это программное обеспечение распространяется в надежде, что оно будет полезным,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * но БЕЗ КАКОЙ-ЛИБО ГАРАНТИИ; даже без подразумеваемой гарантии
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * КОММЕРЧЕСКОЙ ПРИГОДНОСТИ или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ.
  * GNU General Public License for more details.
+ * Подробности смотрите в GNU General Public License.
  *
  * You should have received a copy of the GNU General Public License
+ * Вы должны были получить копию GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * вместе с этой программой. Если нет, посмотрите <http://www.gnu.org/licenses/>.
  */
 
 package build
@@ -28,45 +39,53 @@ import (
 	"plemya-x.ru/alr/pkg/loggerctx"
 )
 
-// InstallPkgs installs native packages via the package manager,
-// then builds and installs the ALR packages
+// InstallPkgs устанавливает нативные пакеты с использованием менеджера пакетов,
+// затем строит и устанавливает пакеты ALR
 func InstallPkgs(ctx context.Context, alrPkgs []db.Package, nativePkgs []string, opts types.BuildOpts) {
-	log := loggerctx.From(ctx)
+	log := loggerctx.From(ctx) // Инициализируем логгер из контекста
 
 	if len(nativePkgs) > 0 {
 		err := opts.Manager.Install(nil, nativePkgs...)
+        // Если есть нативные пакеты, выполняем их установку
 		if err != nil {
 			log.Fatal("Error installing native packages").Err(err).Send()
+            // Логируем и завершаем выполнение при ошибке
 		}
 	}
 
 	InstallScripts(ctx, GetScriptPaths(ctx, alrPkgs), opts)
+    // Устанавливаем скрипты сборки через функцию InstallScripts
 }
 
-// GetScriptPaths returns a slice of script paths corresponding to the
-// given packages
+// GetScriptPaths возвращает срез путей к скриптам, соответствующий
+// данным пакетам
 func GetScriptPaths(ctx context.Context, pkgs []db.Package) []string {
 	var scripts []string
 	for _, pkg := range pkgs {
+        // Для каждого пакета создаем путь к скрипту сборки
 		scriptPath := filepath.Join(config.GetPaths(ctx).RepoDir, pkg.Repository, pkg.Name, "alr.sh")
 		scripts = append(scripts, scriptPath)
 	}
 	return scripts
 }
 
-// InstallScripts builds and installs the given alr build scripts
+// InstallScripts строит и устанавливает переданные alr скрипты сборки
 func InstallScripts(ctx context.Context, scripts []string, opts types.BuildOpts) {
-	log := loggerctx.From(ctx)
+	log := loggerctx.From(ctx) // Получаем логгер из контекста
 	for _, script := range scripts {
-		opts.Script = script
+		opts.Script = script // Устанавливаем текущий скрипт в опции
 		builtPkgs, _, err := BuildPackage(ctx, opts)
+        // Выполняем сборку пакета
 		if err != nil {
 			log.Fatal("Error building package").Err(err).Send()
+            // Логируем и завершаем выполнение при ошибке сборки
 		}
 
 		err = opts.Manager.InstallLocal(nil, builtPkgs...)
+        // Устанавливаем локально собранные пакеты
 		if err != nil {
 			log.Fatal("Error installing package").Err(err).Send()
+            // Логируем и завершаем выполнение при ошибке установки
 		}
 	}
 }
diff --git a/pkg/gen/funcs.go b/pkg/gen/funcs.go
index c0b6c51..46022e3 100644
--- a/pkg/gen/funcs.go
+++ b/pkg/gen/funcs.go
@@ -1,13 +1,20 @@
 package gen
 
 import (
-	"strings"
-	"text/template"
+    "strings"
+    "text/template"
 )
 
+// Определяем переменную funcs типа template.FuncMap, которая будет использоваться для
+// предоставления пользовательских функций в шаблонах
 var funcs = template.FuncMap{
-	"tolower": strings.ToLower,
-	"firstchar": func(s string) string {
-		return s[:1]
-	},
+    // Функция "tolower" использует strings.ToLower
+    // для преобразования строки в нижний регистр
+    "tolower": strings.ToLower,
+
+    // Функция "firstchar" — это лямбда-функция, которая берет строку
+    // и возвращает её первый символ
+    "firstchar": func(s string) string {
+        return s[:1]
+    },
 }
diff --git a/pkg/gen/pip.go b/pkg/gen/pip.go
index 6f8f984..c9a7384 100644
--- a/pkg/gen/pip.go
+++ b/pkg/gen/pip.go
@@ -1,84 +1,98 @@
 package gen
 
 import (
-	_ "embed"
-	"encoding/json"
-	"errors"
-	"fmt"
-	"io"
-	"net/http"
-	"text/template"
+    _ "embed" // Пакет для встраивания содержимого файлов в бинарники Go, использовав откладку //go:embed
+    "encoding/json" // Пакет для работы с JSON: декодирование и кодирование
+    "errors"    // Пакет для создания и обработки ошибок
+    "fmt"       // Пакет для форматированного ввода и вывода
+    "io"        // Пакет для интерфейсов ввода и вывода
+    "net/http"  // Пакет для HTTP-клиентов и серверов
+    "text/template" // Пакет для обработки текстовых шаблонов
 )
 
+// Используем директиву //go:embed для встраивания содержимого файла шаблона в строку pipTmpl
+// Встраивание файла tmpls/pip.tmpl.sh
 //go:embed tmpls/pip.tmpl.sh
 var pipTmpl string
 
+// PipOptions содержит параметры, которые будут переданы в шаблон
 type PipOptions struct {
-	Name        string
-	Version     string
-	Description string
+    Name        string // Имя пакета
+    Version     string // Версия пакета
+    Description string // Описание пакета
 }
 
+// pypiAPIResponse представляет структуру ответа от API PyPI
 type pypiAPIResponse struct {
-	Info pypiInfo  `json:"info"`
-	URLs []pypiURL `json:"urls"`
+    Info pypiInfo  `json:"info"` // Информация о пакете
+    URLs []pypiURL `json:"urls"` // Список URL-адресов для загрузки пакета
 }
 
+// Метод SourceURL ищет и возвращает URL исходного distribution для пакета, если он существует
 func (res pypiAPIResponse) SourceURL() (pypiURL, error) {
-	for _, url := range res.URLs {
-		if url.PackageType == "sdist" {
-			return url, nil
-		}
-	}
-	return pypiURL{}, errors.New("package doesn't have a source distribution")
+    for _, url := range res.URLs {
+        if url.PackageType == "sdist" {
+            return url, nil
+        }
+    }
+    return pypiURL{}, errors.New("package doesn't have a source distribution")
 }
 
+// pypiInfo содержит основную информацию о пакете, такую как имя, версия и пр.
 type pypiInfo struct {
-	Name     string `json:"name"`
-	Version  string `json:"version"`
-	Summary  string `json:"summary"`
-	Homepage string `json:"home_page"`
-	License  string `json:"license"`
+    Name     string `json:"name"`
+    Version  string `json:"version"`
+    Summary  string `json:"summary"`
+    Homepage string `json:"home_page"`
+    License  string `json:"license"`
 }
 
+// pypiURL представляет информацию об одном из доступных для загрузки URL
 type pypiURL struct {
-	Digests     map[string]string `json:"digests"`
-	Filename    string            `json:"filename"`
-	PackageType string            `json:"packagetype"`
+    Digests     map[string]string `json:"digests"` // Контрольные суммы для файлов
+    Filename    string            `json:"filename"` // Имя файла
+    PackageType string            `json:"packagetype"` // Тип пакета (например sdist)
 }
 
+// Функция Pip загружает информацию о пакете из PyPI и использует шаблон для вывода информации
 func Pip(w io.Writer, opts PipOptions) error {
-	tmpl, err := template.New("pip").
-		Funcs(funcs).
-		Parse(pipTmpl)
-	if err != nil {
-		return err
-	}
+    // Создаем новый шаблон с добавлением функций из FuncMap
+    tmpl, err := template.New("pip").
+        Funcs(funcs).
+        Parse(pipTmpl)
+    if err != nil {
+        return err
+    }
 
-	url := fmt.Sprintf(
-		"https://pypi.org/pypi/%s/%s/json",
-		opts.Name,
-		opts.Version,
-	)
+    // Формируем URL для запроса к PyPI на основании имени и версии пакета
+    url := fmt.Sprintf(
+        "https://pypi.org/pypi/%s/%s/json",
+        opts.Name,
+        opts.Version,
+    )
 
-	res, err := http.Get(url)
-	if err != nil {
-		return err
-	}
-	defer res.Body.Close()
-	if res.StatusCode != 200 {
-		return fmt.Errorf("pypi: %s", res.Status)
-	}
+    // Выполняем HTTP GET запрос к PyPI
+    res, err := http.Get(url)
+    if err != nil {
+        return err
+    }
+    defer res.Body.Close() // Закрываем тело ответа после завершения работы
+    if res.StatusCode != 200 {
+        return fmt.Errorf("pypi: %s", res.Status)
+    }
 
-	var resp pypiAPIResponse
-	err = json.NewDecoder(res.Body).Decode(&resp)
-	if err != nil {
-		return err
-	}
+    // Раскодируем ответ JSON от PyPI в структуру pypiAPIResponse
+    var resp pypiAPIResponse
+    err = json.NewDecoder(res.Body).Decode(&resp)
+    if err != nil {
+        return err
+    }
 
-	if opts.Description != "" {
-		resp.Info.Summary = opts.Description
-	}
+    // Если в opts указано описание, используем его вместо описания из PyPI
+    if opts.Description != "" {
+        resp.Info.Summary = opts.Description
+    }
 
-	return tmpl.Execute(w, resp)
+    // Выполняем шаблон с использованием данных из resp и записываем результат в w
+    return tmpl.Execute(w, resp)
 }
diff --git a/pkg/manager/dnf.go b/pkg/manager/dnf.go
index 7f9fc6f..c97c573 100644
--- a/pkg/manager/dnf.go
+++ b/pkg/manager/dnf.go
@@ -1,160 +1,172 @@
 /*
  * ALR - Any Linux Repository
+ * ALR - Любой Linux Репозиторий
  * Copyright (C) 2024 Евгений Храмов
  *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * This program является свободным: вы можете распространять его и/или изменять
+ * на условиях GNU General Public License, опубликованной Free Software Foundation,
+ * либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Это программное обеспечение распространяется в надежде, что оно будет полезным,
+ * но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ; без подразумеваемой гарантии
+ * КОММЕРЧЕСКОЙ ПРИГОДНОСТИ или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ.
+ * Подробности см. в GNU General Public License.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * Вы должны были получить копию GNU General Public License
+ * вместе с этой программой. Если нет, см. <http://www.gnu.org/licenses/>.
  */
 
 package manager
 
 import (
-	"bufio"
-	"fmt"
-	"os/exec"
-	"strings"
+    "bufio"
+    "fmt"
+    "os/exec"
+    "strings"
 )
 
-// DNF represents the DNF package manager
+// DNF представляет менеджер пакетов DNF
 type DNF struct {
-	rootCmd string
+    rootCmd string  // rootCmd хранит команду, используемую для выполнения команд с правами root
 }
 
+// Exists проверяет, доступен ли DNF в системе, возвращает true если да
 func (*DNF) Exists() bool {
-	_, err := exec.LookPath("dnf")
-	return err == nil
+    _, err := exec.LookPath("dnf")
+    return err == nil
 }
 
+// Name возвращает имя менеджера пакетов, в данном случае "dnf"
 func (*DNF) Name() string {
-	return "dnf"
+    return "dnf"
 }
 
+// Format возвращает формат пакетов "rpm", используемый DNF
 func (*DNF) Format() string {
-	return "rpm"
+    return "rpm"
 }
 
+// SetRootCmd устанавливает команду, используемую для выполнения операций с правами root
 func (d *DNF) SetRootCmd(s string) {
-	d.rootCmd = s
+    d.rootCmd = s
 }
 
+// Sync выполняет upgrade всех установленных пакетов, обновляя их до более новых версий
 func (d *DNF) Sync(opts *Opts) error {
-	opts = ensureOpts(opts)
-	cmd := d.getCmd(opts, "dnf", "upgrade")
-	setCmdEnv(cmd)
-	err := cmd.Run()
-	if err != nil {
-		return fmt.Errorf("dnf: sync: %w", err)
-	}
-	return nil
+    opts = ensureOpts(opts)  // Гарантирует, что opts не равен nil и содержит допустимые значения
+    cmd := d.getCmd(opts, "dnf", "upgrade")
+    setCmdEnv(cmd)  // Устанавливает переменные окружения для команды
+    err := cmd.Run()  // Выполняет команду
+    if err != nil {
+        return fmt.Errorf("dnf: sync: %w", err)
+    }
+    return nil
 }
 
+// Install устанавливает указанные пакеты с помощью DNF
 func (d *DNF) Install(opts *Opts, pkgs ...string) error {
-	opts = ensureOpts(opts)
-	cmd := d.getCmd(opts, "dnf", "install", "--allowerasing")
-	cmd.Args = append(cmd.Args, pkgs...)
-	setCmdEnv(cmd)
-	err := cmd.Run()
-	if err != nil {
-		return fmt.Errorf("dnf: install: %w", err)
-	}
-	return nil
+    opts = ensureOpts(opts)
+    cmd := d.getCmd(opts, "dnf", "install", "--allowerasing")
+    cmd.Args = append(cmd.Args, pkgs...)  // Добавляем названия пакетов к команде
+    setCmdEnv(cmd)
+    err := cmd.Run()
+    if err != nil {
+        return fmt.Errorf("dnf: install: %w", err)
+    }
+    return nil
 }
 
+// InstallLocal расширяет метод Install для установки пакетов, расположенных локально
 func (d *DNF) InstallLocal(opts *Opts, pkgs ...string) error {
-	opts = ensureOpts(opts)
-	return d.Install(opts, pkgs...)
+    opts = ensureOpts(opts)
+    return d.Install(opts, pkgs...)
 }
 
+// Remove удаляет указанные пакеты с помощью DNF
 func (d *DNF) Remove(opts *Opts, pkgs ...string) error {
-	opts = ensureOpts(opts)
-	cmd := d.getCmd(opts, "dnf", "remove")
-	cmd.Args = append(cmd.Args, pkgs...)
-	setCmdEnv(cmd)
-	err := cmd.Run()
-	if err != nil {
-		return fmt.Errorf("dnf: remove: %w", err)
-	}
-	return nil
+    opts = ensureOpts(opts)
+    cmd := d.getCmd(opts, "dnf", "remove")
+    cmd.Args = append(cmd.Args, pkgs...)
+    setCmdEnv(cmd)
+    err := cmd.Run()
+    if err != nil {
+        return fmt.Errorf("dnf: remove: %w", err)
+    }
+    return nil
 }
 
+// Upgrade обновляет указанные пакеты до более новых версий
 func (d *DNF) Upgrade(opts *Opts, pkgs ...string) error {
-	opts = ensureOpts(opts)
-	cmd := d.getCmd(opts, "dnf", "upgrade")
-	cmd.Args = append(cmd.Args, pkgs...)
-	setCmdEnv(cmd)
-	err := cmd.Run()
-	if err != nil {
-		return fmt.Errorf("dnf: upgrade: %w", err)
-	}
-	return nil
+    opts = ensureOpts(opts)
+    cmd := d.getCmd(opts, "dnf", "upgrade")
+    cmd.Args = append(cmd.Args, pkgs...)
+    setCmdEnv(cmd)
+    err := cmd.Run()
+    if err != nil {
+        return fmt.Errorf("dnf: upgrade: %w", err)
+    }
+    return nil
 }
 
+// UpgradeAll обновляет все установленные пакеты
 func (d *DNF) UpgradeAll(opts *Opts) error {
-	opts = ensureOpts(opts)
-	cmd := d.getCmd(opts, "dnf", "upgrade")
-	setCmdEnv(cmd)
-	err := cmd.Run()
-	if err != nil {
-		return fmt.Errorf("dnf: upgradeall: %w", err)
-	}
-	return nil
+    opts = ensureOpts(opts)
+    cmd := d.getCmd(opts, "dnf", "upgrade")
+    setCmdEnv(cmd)
+    err := cmd.Run()
+    if err != nil {
+        return fmt.Errorf("dnf: upgradeall: %w", err)
+    }
+    return nil
 }
 
+// ListInstalled возвращает список установленных пакетов и их версий
 func (d *DNF) ListInstalled(opts *Opts) (map[string]string, error) {
-	out := map[string]string{}
-	cmd := exec.Command("rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")
+    out := map[string]string{}
+    cmd := exec.Command("rpm", "-qa", "--queryformat", "%{NAME}\u200b%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}\\n")
 
-	stdout, err := cmd.StdoutPipe()
-	if err != nil {
-		return nil, err
-	}
+    stdout, err := cmd.StdoutPipe()
+    if err != nil {
+        return nil, err
+    }
 
-	err = cmd.Start()
-	if err != nil {
-		return nil, err
-	}
+    err = cmd.Start()
+    if err != nil {
+        return nil, err
+    }
 
-	scanner := bufio.NewScanner(stdout)
-	for scanner.Scan() {
-		name, version, ok := strings.Cut(scanner.Text(), "\u200b")
-		if !ok {
-			continue
-		}
-		version = strings.TrimPrefix(version, "0:")
-		out[name] = version
-	}
+    scanner := bufio.NewScanner(stdout)
+    for scanner.Scan() {
+        name, version, ok := strings.Cut(scanner.Text(), "\u200b")
+        if !ok {
+            continue
+        }
+        version = strings.TrimPrefix(version, "0:")
+        out[name] = version
+    }
 
-	err = scanner.Err()
-	if err != nil {
-		return nil, err
-	}
+    err = scanner.Err()
+    if err != nil {
+        return nil, err
+    }
 
-	return out, nil
+    return out, nil
 }
 
+// getCmd создает и возвращает команду exec.Cmd для менеджера пакетов DNF
 func (d *DNF) getCmd(opts *Opts, mgrCmd string, args ...string) *exec.Cmd {
-	var cmd *exec.Cmd
-	if opts.AsRoot {
-		cmd = exec.Command(getRootCmd(d.rootCmd), mgrCmd)
-		cmd.Args = append(cmd.Args, opts.Args...)
-		cmd.Args = append(cmd.Args, args...)
-	} else {
-		cmd = exec.Command(mgrCmd, args...)
-	}
+    var cmd *exec.Cmd
+    if opts.AsRoot {
+        cmd = exec.Command(getRootCmd(d.rootCmd), mgrCmd)
+        cmd.Args = append(cmd.Args, opts.Args...)
+        cmd.Args = append(cmd.Args, args...)
+    } else {
+        cmd = exec.Command(mgrCmd, args...)
+    }
 
-	if opts.NoConfirm {
-		cmd.Args = append(cmd.Args, "-y")
-	}
+    if opts.NoConfirm {
+        cmd.Args = append(cmd.Args, "-y")  // Добавляет параметр автоматического подтверждения (-y)
+    }
 
-	return cmd
+    return cmd
 }