우리는 이와 같은 간단한 yaml 파일을 사용하여 작업 실행을 사용할 수 있는 make와 같은 도구를 만들 것입니다.
tasks: build: description: "compile the project" command: "go build main.go" dependencies: [test] test: description: "run unit tests" command: "go test -v ./..."
시작하겠습니다. 먼저 조치 과정을 개략적으로 설명해야 합니다. 우리는 이미 작업 파일 스키마를 정의했습니다. yaml 대신 json을 사용할 수 있지만 이 프로젝트에서는 yml 파일을 사용하겠습니다.
파일에서 단일 작업을 저장하기 위한 구조체와 기본 작업을 진행하기 전에 종속 작업을 실행하는 방법이 필요하다는 것을 알 수 있습니다. 프로젝트를 시작하는 것부터 시작해 보겠습니다. 새 폴더를 만들고 다음을 실행하세요.
go mod init github.com/vishaaxl/mommy
프로젝트 이름은 원하는 대로 지정할 수 있습니다. 저는 '엄마' 이름을 사용하겠습니다. 또한 yaml 파일을 사용하려면 일부 패키지를 설치해야 합니다. 기본적으로 해당 파일을 지도 객체로 변환합니다. 다음 패키지를 설치해 보세요.
go get gopkg.in/yaml.v3
다음으로 새 main.go 파일을 만들고 'Task' 구조체 정의부터 시작합니다.
package main import ( "gopkg.in/yaml.v3" ) // Task defines the structure of a task in the configuration file. // Each task has a description, a command to run, and a list of dependencies // (other tasks that need to be completed before this task). type Task struct { Description string `yaml:"description"` // A brief description of the task. Command string `yaml:"command"` // The shell command to execute for the task. Dependencies []string `yaml:"dependencies"` // List of tasks that need to be completed before this task. }
이것은 꽤 자명합니다. 이는 각 개별 작업의 가치를 유지합니다. 다음으로 작업 목록을 저장하고 .yaml 파일의 내용을 이 새 개체에 로드하려면 구조체가 하나 더 필요합니다.
// Config represents the entire configuration file, // which contains a map of tasks by name. type Config struct { Tasks map[string]Task `yaml:"tasks"` // A map of task names to task details. } // loadConfig reads and parses the configuration file (e.g., Makefile.yaml), // and returns a Config struct containing the tasks and their details. func loadConfig(filename string) (Config, error) { // Read the content of the config file. data, err := os.ReadFile(filename) if err != nil { return Config{}, err } // Unmarshal the YAML data into a Config struct. var config Config err = yaml.Unmarshal(data, &config) if err != nil { return Config{}, err } return config, nil }
다음으로 단일 작업을 실행하는 함수를 만들어야 합니다. 우리는 쉘에서 작업을 실행하기 위해 os/exec 모듈을 사용할 것입니다. Golang에서 os/exec 패키지는 셸 명령과 외부 프로그램을 실행하는 방법을 제공합니다.
// executeTask recursively executes the specified task and its dependencies. // It first ensures that all dependencies are executed before running the current task's command. func executeTask(taskName string, tasks map[string]Task, executed map[string]bool) error { // If the task has already been executed, skip it. if executed[taskName] { return nil } // Get the task details from the tasks map. task, exists := tasks[taskName] if !exists { return fmt.Errorf("task %s not found", taskName) } // First, execute all the dependencies of this task. for _, dep := range task.Dependencies { // Recursively execute each dependency. if err := executeTask(dep, tasks, executed); err != nil { return err } } // Now that dependencies are executed, run the task's command. fmt.Printf("Running task: %s\n", taskName) fmt.Printf("Command: %s\n", task.Command) // Execute the task's command using the shell (sh -c allows for complex shell commands). cmd := exec.Command("sh", "-c", task.Command) cmd.Stdout = os.Stdout // Direct standard output to the terminal. cmd.Stderr = os.Stderr // Direct error output to the terminal. // Run the command and check for any errors. if err := cmd.Run(); err != nil { return fmt.Errorf("failed to execute command %s: %v", task.Command, err) } // Mark the task as executed. executed[taskName] = true return nil }
이제 구성 파일을 로드하고 자동화를 시작하기 위해 기본 기능에서 사용할 수 있는 프로그램의 모든 구성 요소가 있습니다. 우리는 명령줄 플래그를 읽기 위해 플래그 패키지를 사용할 것입니다.
func main() { // Define command-line flags configFile := flag.String("f", "Mommy.yaml", "Path to the configuration file") // Path to the config file (defaults to Makefile.yaml) taskName := flag.String("task", "", "Task to execute") // The task to execute (required flag) // Parse the flags flag.Parse() // Check if the task flag is provided if *taskName == "" { fmt.Println("Error: Please specify a task using -task flag.") os.Exit(1) // Exit if no task is provided } // Load the configuration file config, err := loadConfig(*configFile) if err != nil { fmt.Printf("Failed to load config: %v\n", err) os.Exit(1) // Exit if the configuration file can't be loaded } // Map to track which tasks have been executed already (avoiding re-execution). executed := make(map[string]bool) // Start executing the specified task (with dependencies) if err := executeTask(*taskName, config.Tasks, executed); err != nil { fmt.Printf("Error executing task: %v\n", err) os.Exit(1) // Exit if task execution fails } }
전체를 테스트하고 새 Mommy.yaml을 생성한 후 처음부터 yaml 코드를 붙여넣어 보겠습니다. 우리는 작업 실행기를 사용하여 프로젝트에 대한 바이너리를 만들 것입니다. 실행:
go run main.go -task build
모든 문제가 해결되면 폴더 루트에 새 .exe 파일이 표시됩니다. 좋습니다. 이제 작업 중인 작업 실행기가 생겼습니다. 시스템의 환경 변수에 이 .exe 파일의 위치를 추가하고 다음을 사용하여 어디에서나 사용할 수 있습니다.
mommy -task build
package main import ( "flag" "fmt" "os" "os/exec" "gopkg.in/yaml.v3" ) // Task defines the structure of a task in the configuration file. // Each task has a description, a command to run, and a list of dependencies // (other tasks that need to be completed before this task). type Task struct { Description string `yaml:"description"` // A brief description of the task. Command string `yaml:"command"` // The shell command to execute for the task. Dependencies []string `yaml:"dependencies"` // List of tasks that need to be completed before this task. } // Config represents the entire configuration file, // which contains a map of tasks by name. type Config struct { Tasks map[string]Task `yaml:"tasks"` // A map of task names to task details. } // loadConfig reads and parses the configuration file (e.g., Makefile.yaml), // and returns a Config struct containing the tasks and their details. func loadConfig(filename string) (Config, error) { // Read the content of the config file. data, err := os.ReadFile(filename) if err != nil { return Config{}, err } // Unmarshal the YAML data into a Config struct. var config Config err = yaml.Unmarshal(data, &config) if err != nil { return Config{}, err } return config, nil } // executeTask recursively executes the specified task and its dependencies. // It first ensures that all dependencies are executed before running the current task's command. func executeTask(taskName string, tasks map[string]Task, executed map[string]bool) error { // If the task has already been executed, skip it. if executed[taskName] { return nil } // Get the task details from the tasks map. task, exists := tasks[taskName] if !exists { return fmt.Errorf("task %s not found", taskName) } // First, execute all the dependencies of this task. for _, dep := range task.Dependencies { // Recursively execute each dependency. if err := executeTask(dep, tasks, executed); err != nil { return err } } // Now that dependencies are executed, run the task's command. fmt.Printf("Running task: %s\n", taskName) fmt.Printf("Command: %s\n", task.Command) // Execute the task's command using the shell (sh -c allows for complex shell commands). cmd := exec.Command("sh", "-c", task.Command) cmd.Stdout = os.Stdout // Direct standard output to the terminal. cmd.Stderr = os.Stderr // Direct error output to the terminal. // Run the command and check for any errors. if err := cmd.Run(); err != nil { return fmt.Errorf("failed to execute command %s: %v", task.Command, err) } // Mark the task as executed. executed[taskName] = true return nil } func main() { // Define command-line flags configFile := flag.String("f", "Makefile.yaml", "Path to the configuration file") // Path to the config file (defaults to Makefile.yaml) taskName := flag.String("task", "", "Task to execute") // The task to execute (required flag) // Parse the flags flag.Parse() // Check if the task flag is provided if *taskName == "" { fmt.Println("Error: Please specify a task using -task flag.") os.Exit(1) // Exit if no task is provided } // Load the configuration file config, err := loadConfig(*configFile) if err != nil { fmt.Printf("Failed to load config: %v\n", err) os.Exit(1) // Exit if the configuration file can't be loaded } // Map to track which tasks have been executed already (avoiding re-execution). executed := make(map[string]bool) // Start executing the specified task (with dependencies) if err := executeTask(*taskName, config.Tasks, executed); err != nil { fmt.Printf("Error executing task: %v\n", err) os.Exit(1) // Exit if task execution fails } }
위 내용은 초보자 Go 프로젝트 - Go에서 작업 실행기 만들기의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!