github.com/go-maxhub/gremlins@v1.0.1-0.20231227222204-b03a6a1e3e09/core/gomodule/gomodule.go (about)

     1  /*
     2   * Copyright 2022 The Gremlins Authors
     3   *
     4   *    Licensed under the Apache License, Version 2.0 (the "License");
     5   *    you may not use this file except in compliance with the License.
     6   *    You may obtain a copy of the License at
     7   *
     8   *        http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   *    Unless required by applicable law or agreed to in writing, software
    11   *    distributed under the License is distributed on an "AS IS" BASIS,
    12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   *    See the License for the specific language governing permissions and
    14   *    limitations under the License.
    15   */
    16  
    17  package gomodule
    18  
    19  import (
    20  	"bufio"
    21  	"bytes"
    22  	"fmt"
    23  	"os"
    24  	"path/filepath"
    25  )
    26  
    27  // GoModule represents the current execution context in Gremlins.
    28  //
    29  //	Name is the module name of the Go module being tested by Gremlins.
    30  //	Root is the root folder of the Go module.
    31  //	CallingDir is the folder in which Gremlins is running.
    32  type GoModule struct {
    33  	Name       string
    34  	Root       string
    35  	CallingDir string
    36  }
    37  
    38  // Init initializes the current module. It finds the module name and the root
    39  // of the module, then returns a GoModule struct.
    40  func Init(path string) (GoModule, error) {
    41  	if path == "" {
    42  		return GoModule{}, fmt.Errorf("path is not set")
    43  	}
    44  	mod, root, err := modPkg(path)
    45  	if err != nil {
    46  		return GoModule{}, err
    47  	}
    48  	path, _ = filepath.Rel(root, path)
    49  
    50  	return GoModule{
    51  		Name:       mod,
    52  		Root:       root,
    53  		CallingDir: path,
    54  	}, nil
    55  }
    56  
    57  func modPkg(path string) (string, string, error) {
    58  	root := findModuleRoot(path)
    59  	file, err := os.Open(root + "/go.mod")
    60  	defer func(file *os.File) {
    61  		_ = file.Close()
    62  	}(file)
    63  	if err != nil {
    64  		return "", "", err
    65  	}
    66  	r := bufio.NewReader(file)
    67  	line, _, err := r.ReadLine()
    68  	if err != nil {
    69  		return "", "", err
    70  	}
    71  	packageName := bytes.TrimPrefix(line, []byte("module "))
    72  
    73  	return string(packageName), root, nil
    74  }
    75  
    76  func findModuleRoot(path string) string {
    77  	// Inspired by how Go itself finds the module root.
    78  	path = filepath.Clean(path)
    79  	for {
    80  		if fi, err := os.Stat(filepath.Join(path, "go.mod")); err == nil && !fi.IsDir() {
    81  			return path
    82  		}
    83  		d := filepath.Dir(path)
    84  		if d == path {
    85  			break
    86  		}
    87  		path = d
    88  	}
    89  
    90  	return ""
    91  }