From 58414744ce1c0a44b9d7aff3544c3a4444c7ba96 Mon Sep 17 00:00:00 2001 From: greenhazz Date: Wed, 20 Aug 2025 21:15:35 +0300 Subject: [PATCH] prototype --- .gitignore | 1 + cmd/main.go | 28 +++++++ go.mod | 3 + internal/build/build_project.go | 45 +++++++++++ internal/create/create_project.go | 51 ++++++++++++ internal/global/project_file.go | 11 +++ internal/target/base_target.go | 7 ++ internal/target/darwin/darwin_target.go | 100 ++++++++++++++++++++++++ internal/target/darwin/template.go | 69 ++++++++++++++++ internal/utils/fsutils.go | 55 +++++++++++++ internal/utils/is_dir_empty.go | 20 +++++ 11 files changed, 390 insertions(+) create mode 100644 .gitignore create mode 100644 cmd/main.go create mode 100644 go.mod create mode 100644 internal/build/build_project.go create mode 100644 internal/create/create_project.go create mode 100644 internal/global/project_file.go create mode 100644 internal/target/base_target.go create mode 100644 internal/target/darwin/darwin_target.go create mode 100644 internal/target/darwin/template.go create mode 100644 internal/utils/fsutils.go create mode 100644 internal/utils/is_dir_empty.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4ace676 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +carga diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..ec692e4 --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,28 @@ +package main + +import ( + "fmt" + "os" + + "git.gulenok.ru/greenhaze/old_carga/internal/build" + "git.gulenok.ru/greenhaze/old_carga/internal/create" +) + +func main() { + execute_action() +} + +// парсит 1 os.Args и вызывает нужный метод +func execute_action() { + action := os.Args[1] + switch action { + case "создай": + create.CreateProject() + case "собери": + build.BuildProject() + case "установи": + fmt.Println("эмулирую установку модуля") + case "добавь_цель": + fmt.Println("Добавляю цель") + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..06f10a5 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.gulenok.ru/greenhaze/old_carga + +go 1.24.1 diff --git a/internal/build/build_project.go b/internal/build/build_project.go new file mode 100644 index 0000000..bd9bfad --- /dev/null +++ b/internal/build/build_project.go @@ -0,0 +1,45 @@ +package build + +import ( + "encoding/json" + "log" + "os" + "path" + + "git.gulenok.ru/greenhaze/old_carga/internal/global" + "git.gulenok.ru/greenhaze/old_carga/internal/target" + "git.gulenok.ru/greenhaze/old_carga/internal/target/darwin" +) + +func BuildProject() { + project_config := parseProjectFile() + bt := getBuildTarget(project_config) + bt.CreateBuildProject(project_config) + log.Println("СТАРАЯ КАРГА ЗАВЕРШИЛА СБОРКУ УСПЕШНО!") + +} +func parseProjectFile() global.ProjectFile { + working_dir, err := os.Getwd() + if err != nil { + log.Fatalln("карга не смогла получить текущую рабочую директорию") + } + file, err := os.ReadFile(path.Join(working_dir, "карга.json")) + if err != nil { + log.Fatalln("карга не смогла прочитать карга.json") + } + var pf global.ProjectFile + json.Unmarshal(file, &pf) + return pf +} +func getBuildTarget(bc global.ProjectFile) target.BaseTarget { + switch bc.Target { + case "darwin": + return darwin.DarwinBuildTarget{} + case "linux": + //пока тут нет linux specific приколов так шо пока пусть будет дарвин, лол + return darwin.DarwinBuildTarget{} + } + log.Fatalf("Неизвестная цель сборки %s", bc.Target) + + return nil +} diff --git a/internal/create/create_project.go b/internal/create/create_project.go new file mode 100644 index 0000000..9cc7a91 --- /dev/null +++ b/internal/create/create_project.go @@ -0,0 +1,51 @@ +package create + +import ( + "encoding/json" + "log" + "os" + "path" + "path/filepath" + "runtime" + + "git.gulenok.ru/greenhaze/old_carga/internal/global" + "git.gulenok.ru/greenhaze/old_carga/internal/utils" +) + +func CreateProject() { + //выдает абсолютный путь (по крайней мере на маке) типо + // /Users/greenhaze/Programming/rela/old_carga + current_dir, err := os.Getwd() + if err != nil { + log.Fatalln("карга не смогла получить текущую директорию") + } + + is_empty, err := utils.IsDirEmpty(current_dir) + if err != nil { + log.Fatalln("карга не смогла проверить является ли текущая директория пустой") + } + if !is_empty { + log.Fatalln("Текущая директория не пустая. Карга не может создать тут проект") + } + createProjectFile(current_dir) + os.Mkdir(path.Join(current_dir, "исх"), 0755) +} +func createProjectFile(dir string) { + // для примера я добавил базовые таргеты + base_file := global.ProjectFile{ + ProjectName: filepath.Base(dir), + Target: runtime.GOOS, + Modules: make([]global.IncludeModule, 0), + } + file_str, err := json.Marshal(&base_file) + if err != nil { + log.Fatalln("Карга не смогла собрать базовый файл. Пните пожалуйста разработчика") + } + carga_project := filepath.Join(dir, "карга.json") + + err = os.WriteFile(carga_project, file_str, 0644) + if err != nil { + log.Fatalln("карга не смогла записать карга.json в директорию") + } + +} diff --git a/internal/global/project_file.go b/internal/global/project_file.go new file mode 100644 index 0000000..a713b88 --- /dev/null +++ b/internal/global/project_file.go @@ -0,0 +1,11 @@ +package global + +type ProjectFile struct { + ProjectName string `json:"project_name"` + Target string `json:"target"` + Modules []IncludeModule `json:"include_modules"` +} +type IncludeModule struct { + CFile string `json:"c_file"` + CHeader string `json:"c_header"` +} diff --git a/internal/target/base_target.go b/internal/target/base_target.go new file mode 100644 index 0000000..b0445a9 --- /dev/null +++ b/internal/target/base_target.go @@ -0,0 +1,7 @@ +package target + +import "git.gulenok.ru/greenhaze/old_carga/internal/global" + +type BaseTarget interface { + CreateBuildProject(config global.ProjectFile) bool +} diff --git a/internal/target/darwin/darwin_target.go b/internal/target/darwin/darwin_target.go new file mode 100644 index 0000000..1c76f44 --- /dev/null +++ b/internal/target/darwin/darwin_target.go @@ -0,0 +1,100 @@ +package darwin + +import ( + "fmt" + "log" + "os" + "os/exec" + "path" + + "git.gulenok.ru/greenhaze/old_carga/internal/global" + "git.gulenok.ru/greenhaze/old_carga/internal/utils" +) + +type DarwinBuildTarget struct { +} + +func (d DarwinBuildTarget) CreateBuildProject(config global.ProjectFile) bool { + //создаем папку в которой будем проводить все наши изуверства + // поскольку я не знаю насколько ниндзя/make дружат с кириллицей, пока что пусть называется build + value, err := os.Getwd() + if err != nil { + log.Fatalln("карга не смогла получить рабочую директорию") + } + os.Mkdir(path.Join(value, "build"), 0755) + //копируем тривиль исходники в build + utils.CopyDir("./исх", "./build/src") + + os.Chdir("./build") + //качаем бинарник компилятора если оного нет и не забываем удалить забытые скрипты + if _, err := os.Stat("./трик"); os.IsNotExist(err) { + log.Println("АХТУНГ. Поскольку это дев билд а у меня адекватно не завелся компилятор, сейчас оно качает бинарь с релиза каждый раз") + + cmd := exec.Command("wget", "https://gitflic.ru/project/alekseinedoria/trivil-0/release/c09308df-49c1-4297-8e1c-a41030933720/df79d7c6-fd81-420c-bb42-6f3115dbbc2c/download") + if err := cmd.Run(); err != nil { + log.Fatal(err) + } + cmd = exec.Command("tar", "-zxf", "download") + if err := cmd.Run(); err != nil { + log.Fatal(err) + } + //а вот это в свою очередь уже костыль потому что из релиза забыли убрать билд кеши + cmd = exec.Command("rm", "-rf", "./_си") + cmd.Stdout = os.Stdout + if err := cmd.Run(); err != nil { + log.Fatal(err) + } + + } + //собираем Тривиль код в Си + cmd := exec.Command("./трик.exe", "-отл-сборка=истина", "-сборка=ложь", "src") + cmd.Stdout = os.Stdout + if err := cmd.Run(); err != nil { + log.Fatalf("сборка триком не удалась %s", err) + } + + // внедряем Си + log.Println(config.Modules) + + for _, v := range config.Modules { + err := utils.CopyFile(fmt.Sprintf("../си/%s", v.CFile), fmt.Sprintf("./_си/%s", v.CFile)) + if err != nil { + log.Fatalf("карга не смогла скопировать Си файл %s", err) + } + } + + //собираем Makefile + files, err := getCFilesInCurrentDir() + if err != nil { + panic(err) + } + out, err := renderMakefile(Vars{ + + FILES: files, + RUNTIME: "../runtime", + TARGET: "target", + }) + if err != nil { + panic(err) + } + err = os.WriteFile("./_си/Makefile", []byte(out), 0644) + if err != nil { + log.Fatalln("Карга не смогла записать Makefile") + } + + os.Chdir("./_си") + // Собираем + cmd = exec.Command("make") + cmd.Stdout = os.Stdout + if err := cmd.Run(); err != nil { + log.Fatalf("сборка make не удалась %s", err) + } + + return true +} + +/* + * + * pushd . && + * cd /home/dmitrys/devel/trivil-project/trivil-0/scripts/rel/_си && clang yunikod.c utf8.c stroki.c vyvod.c fnv.c komstroka.c platforma.c fayily.c str_str.c osh_soobshcheniya.c osnova.c klyuchevye_slova.c lekser.c asd.c asd_pokaz.c slovar__moduli.c slovar__sostoyanie.c slovar__opisaniyi.c imena.c slovar__tcel_tcel.c kontrol_.c semantika.c perevod_imen.c str_log.c imena_opisaniyi.c imena_tipov.c si.c ar.c gen.c parser.c slovar__importy.c kompilyator.c trik.c /home/dmitrys/devel/trivil-project/trivil-0/scripts/rel/runtime/rt_api.c /home/dmitrys/devel/trivil-project/trivil-0/scripts/rel/runtime/rt_sysapi.c /home/dmitrys/devel/trivil-project/trivil-0/scripts/rel/runtime/rt_syscrash_linux.c -lm -rdynamic -I/home/dmitrys/devel/trivil-project/trivil-0/scripts/rel/runtime -o ../трик.exe && popd + */ diff --git a/internal/target/darwin/template.go b/internal/target/darwin/template.go new file mode 100644 index 0000000..b30e718 --- /dev/null +++ b/internal/target/darwin/template.go @@ -0,0 +1,69 @@ +package darwin + +import ( + "bytes" + "io/ioutil" + "path/filepath" + "strings" + "text/template" +) + +const makefileTemplate = `# Автогенерируемый Makefile +FILES := {{.FILES}} +RUNTIME := {{.RUNTIME}} +TARGET := {{.TARGET}} + +CC := clang +CFLAGS := -I$(RUNTIME) -o3 +LDFLAGS := -lm -rdynamic + +SRCS := $(FILES) \ + $(RUNTIME)/rt_api.c \ + $(RUNTIME)/rt_sysapi.c \ + $(RUNTIME)/rt_syscrash_linux.c + +OUT := ../$(TARGET).exe + +.PHONY: darwin-build clean + +darwin-build: + $(CC) $(SRCS) $(CFLAGS) $(LDFLAGS) -o $(OUT) + +clean: + rm -f $(OUT) + +` + +type Vars struct { + FILES string + RUNTIME string + TARGET string +} + +func getCFilesInCurrentDir() (string, error) { + files, err := ioutil.ReadDir("./_си") + if err != nil { + return "", err + } + + var cFiles []string + for _, f := range files { + if !f.IsDir() && filepath.Ext(f.Name()) == ".c" { + cFiles = append(cFiles, f.Name()) + } + } + + return strings.Join(cFiles, " "), nil +} + +func renderMakefile(vars Vars) (string, error) { + tmpl, err := template.New("makefile").Parse(makefileTemplate) + if err != nil { + return "", err + } + var buf bytes.Buffer + if err := tmpl.Execute(&buf, vars); err != nil { + return "", err + } + return buf.String(), nil +} diff --git a/internal/utils/fsutils.go b/internal/utils/fsutils.go new file mode 100644 index 0000000..0202a44 --- /dev/null +++ b/internal/utils/fsutils.go @@ -0,0 +1,55 @@ +package utils + +import ( + "io" + "log" + "os" + "path/filepath" +) + +func CopyFile(src, dst string) error { + log.Printf("копирую %s в %s", src, dst) + sourceFile, err := os.Open(src) + if err != nil { + return err + } + defer sourceFile.Close() + + // create destination folder if not exist + if err = os.MkdirAll(filepath.Dir(dst), os.ModePerm); err != nil { + return err + } + + destinationFile, err := os.Create(dst) + if err != nil { + return err + } + defer destinationFile.Close() + + _, err = io.Copy(destinationFile, sourceFile) + return err +} + +// CopyDir recursively copies a directory tree +func CopyDir(src string, dst string) error { + return filepath.Walk(src, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + // Construct new path + relPath, err := filepath.Rel(src, path) + if err != nil { + return err + } + targetPath := filepath.Join(dst, relPath) + + if info.IsDir() { + // create directory + return os.MkdirAll(targetPath, info.Mode()) + } else { + // copy file + return CopyFile(path, targetPath) + } + }) +} diff --git a/internal/utils/is_dir_empty.go b/internal/utils/is_dir_empty.go new file mode 100644 index 0000000..f5212e0 --- /dev/null +++ b/internal/utils/is_dir_empty.go @@ -0,0 +1,20 @@ +package utils + +import ( + "io" + "os" +) + +func IsDirEmpty(name string) (bool, error) { + f, err := os.Open(name) + if err != nil { + return false, err + } + defer f.Close() + + _, err = f.Readdirnames(1) // Or f.Readdir(1) + if err == io.EOF { + return true, nil + } + return false, err // Either not empty or error, suits both cases +}