> 백엔드 개발 > Golang > 초보자 Go 프로젝트 - Go에서 작업 실행기 만들기

초보자 Go 프로젝트 - Go에서 작업 실행기 만들기

Linda Hamilton
풀어 주다: 2024-12-30 17:07:10
원래의
614명이 탐색했습니다.

Beginner Go Project - Create a Task Runner in Go

우리가 만들려는 것

우리는 이와 같은 간단한 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿