github.com/influx6/npkg@v0.8.8/ngpkg/pkg.go (about)

     1  // Package ngpkg provides a package interfacing API using the go build
     2  // libraries to provide high level functions that simplify and running
     3  // building processes.
     4  //
     5  package ngpkg
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"go/build"
    11  	"log"
    12  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"regexp"
    16  	"runtime"
    17  	"strings"
    18  )
    19  
    20  var multispaces = regexp.MustCompile(`\s+`)
    21  
    22  // GoDeps calls go get for specific package
    23  func GoDeps(targetdir string) error {
    24  	defer func() {
    25  		if err := recover(); err != nil {
    26  			log.Printf("godeps.Error: %+s", err)
    27  		}
    28  	}()
    29  
    30  	cmdline := []string{"go", "get"}
    31  
    32  	cmdline = append(cmdline, targetdir)
    33  
    34  	//setup the executor and use a shard buffer
    35  	cmd := exec.Command("go", cmdline[1:]...)
    36  	buf := bytes.NewBuffer([]byte{})
    37  	cmd.Stdout = buf
    38  	cmd.Stderr = buf
    39  
    40  	err := cmd.Run()
    41  
    42  	if buf.Len() > 0 {
    43  		return fmt.Errorf("go get failed: %s: %s", buf.String(), err.Error())
    44  	}
    45  
    46  	return nil
    47  }
    48  
    49  // GoRun runs the runs a command
    50  func GoRun(cmd string) string {
    51  	defer func() {
    52  		if err := recover(); err != nil {
    53  			log.Printf("gorun.Error: %+s", err)
    54  		}
    55  	}()
    56  	var cmdline []string
    57  	com := strings.Split(cmd, " ")
    58  
    59  	if len(com) < 0 {
    60  		return ""
    61  	}
    62  
    63  	if len(com) == 1 {
    64  		cmdline = append(cmdline, com...)
    65  	} else {
    66  		cmdline = append(cmdline, com[0])
    67  		cmdline = append(cmdline, com[1:]...)
    68  	}
    69  
    70  	//setup the executor and use a shard buffer
    71  	cmdo := exec.Command(cmdline[0], cmdline[1:]...)
    72  	buf := bytes.NewBuffer([]byte{})
    73  	cmdo.Stdout = buf
    74  	cmdo.Stderr = buf
    75  
    76  	_ = cmdo.Run()
    77  
    78  	return buf.String()
    79  }
    80  
    81  // GobuildArgs runs the build process against a directory, using the giving
    82  // arguments. Returns a non-nil error if it fails.
    83  func GobuildArgs(args []string) error {
    84  	if len(args) <= 0 {
    85  		return nil
    86  	}
    87  
    88  	defer func() {
    89  		if err := recover(); err != nil {
    90  			log.Printf("gobuild.Error: %+s", err)
    91  		}
    92  	}()
    93  
    94  	cmdline := []string{"go", "build"}
    95  
    96  	// target := filepath.Join(dir, name)
    97  	cmdline = append(cmdline, args...)
    98  
    99  	//setup the executor and use a shard buffer
   100  	cmd := exec.Command("go", cmdline[1:]...)
   101  	buf := bytes.NewBuffer([]byte{})
   102  
   103  	msg, err := cmd.CombinedOutput()
   104  
   105  	if !cmd.ProcessState.Success() {
   106  		return fmt.Errorf("go.build failed: %s: %s -> Msg: %s", buf.String(), err.Error(), msg)
   107  	}
   108  
   109  	return nil
   110  }
   111  
   112  // Gobuild runs the build process against a directory, using a giving name for the
   113  // build file. Returns a non-nil error if it fails.
   114  func Gobuild(dir, name string, args []string) error {
   115  	defer func() {
   116  		if err := recover(); err != nil {
   117  			log.Printf("gobuild.Error: %+s", err)
   118  		}
   119  	}()
   120  
   121  	cmdline := []string{"go", "build"}
   122  
   123  	if runtime.GOOS == "windows" {
   124  		name = fmt.Sprintf("%s.exe", name)
   125  	}
   126  
   127  	target := filepath.Join(dir, name)
   128  	cmdline = append(cmdline, args...)
   129  	cmdline = append(cmdline, "-o", target)
   130  
   131  	//setup the executor and use a shard buffer
   132  	cmd := exec.Command("go", cmdline[1:]...)
   133  	buf := bytes.NewBuffer([]byte{})
   134  
   135  	msg, err := cmd.CombinedOutput()
   136  
   137  	if !cmd.ProcessState.Success() {
   138  		return fmt.Errorf("go.build failed: %s: %s -> Msg: %s", buf.String(), err.Error(), msg)
   139  	}
   140  
   141  	return nil
   142  }
   143  
   144  // RunCMD runs the a set of commands from a list while skipping any one-length command, panics if it gets an empty lists
   145  func RunCMD(cmds []string, done func()) chan bool {
   146  	if len(cmds) < 0 {
   147  		panic("commands list cant be empty")
   148  	}
   149  
   150  	var relunch = make(chan bool)
   151  
   152  	go func() {
   153  		defer func() {
   154  			if err := recover(); err != nil {
   155  				log.Printf("cmdRun.Error: %+s", err)
   156  			}
   157  		}()
   158  
   159  	cmdloop:
   160  		for {
   161  			select {
   162  			case do, ok := <-relunch:
   163  
   164  				if !ok {
   165  					break cmdloop
   166  				}
   167  
   168  				if !do {
   169  					continue
   170  				}
   171  
   172  				for _, cox := range cmds {
   173  
   174  					cmd := strings.Split(cox, " ")
   175  
   176  					if len(cmd) <= 1 {
   177  						continue
   178  					}
   179  
   180  					cmdo := exec.Command(cmd[0], cmd[1:]...)
   181  					cmdo.Stdout = os.Stdout
   182  					cmdo.Stderr = os.Stderr
   183  
   184  					if err := cmdo.Start(); err != nil {
   185  						fmt.Printf("---> Error executing command: %s -> %s\n", cmd, err)
   186  					}
   187  				}
   188  
   189  				if done != nil {
   190  					done()
   191  				}
   192  			}
   193  		}
   194  
   195  	}()
   196  	return relunch
   197  }
   198  
   199  // RunGo runs the generated binary file with the arguments expected
   200  func RunGo(gofile string, args []string, done, stopped func()) chan bool {
   201  	var relunch = make(chan bool)
   202  
   203  	// if runtime.GOOS == "windows" {
   204  	gofile = filepath.Clean(gofile)
   205  	// }
   206  
   207  	go func() {
   208  
   209  		// var cmdline = fmt.Sprintf("go run %s", gofile)
   210  		cmdargs := append([]string{"run", gofile}, args...)
   211  		// cmdline = strings.Joinappend([]string{}, "go run", gofile)
   212  
   213  		var proc *os.Process
   214  
   215  		for dosig := range relunch {
   216  			if proc != nil {
   217  				var err error
   218  
   219  				if runtime.GOOS == "windows" {
   220  					err = proc.Kill()
   221  				} else {
   222  					err = proc.Signal(os.Interrupt)
   223  				}
   224  
   225  				if err != nil {
   226  					fmt.Printf("---> Error in Sending Kill Signal %s\n", err)
   227  					proc.Kill()
   228  				}
   229  				proc.Wait()
   230  				proc = nil
   231  			}
   232  
   233  			if !dosig {
   234  				continue
   235  			}
   236  
   237  			cmd := exec.Command("go", cmdargs...)
   238  			cmd.Stdout = os.Stdout
   239  			cmd.Stderr = os.Stderr
   240  
   241  			if err := cmd.Start(); err != nil {
   242  				fmt.Printf("---> Error starting process: %s\n", err)
   243  			}
   244  
   245  			proc = cmd.Process
   246  			if done != nil {
   247  				done()
   248  			}
   249  		}
   250  
   251  		if stopped != nil {
   252  			stopped()
   253  		}
   254  	}()
   255  	return relunch
   256  }
   257  
   258  // RunBin runs the generated binary file with the arguments expected
   259  func RunBin(binfile string, args []string, done, stopped func()) chan bool {
   260  	var relunch = make(chan bool)
   261  	go func() {
   262  		// binfile := fmt.Sprintf("%s/%s", bindir, bin)
   263  		// cmdline := append([]string{bin}, args...)
   264  		var proc *os.Process
   265  
   266  		for dosig := range relunch {
   267  			if proc != nil {
   268  				var err error
   269  
   270  				if runtime.GOOS == "windows" {
   271  					err = proc.Kill()
   272  				} else {
   273  					err = proc.Signal(os.Interrupt)
   274  				}
   275  
   276  				if err != nil {
   277  					fmt.Printf("---> Error in Sending Kill Signal: %s\n", err)
   278  					proc.Kill()
   279  				}
   280  				proc.Wait()
   281  				proc = nil
   282  			}
   283  
   284  			if !dosig {
   285  				continue
   286  			}
   287  
   288  			cmd := exec.Command(binfile, args...)
   289  			cmd.Stdout = os.Stdout
   290  			cmd.Stderr = os.Stderr
   291  
   292  			if err := cmd.Start(); err != nil {
   293  				fmt.Printf("---> Error starting process: %s -> %s\n", binfile, err)
   294  			}
   295  
   296  			proc = cmd.Process
   297  			if done != nil {
   298  				done()
   299  			}
   300  		}
   301  
   302  		if stopped != nil {
   303  			stopped()
   304  		}
   305  	}()
   306  	return relunch
   307  }
   308  
   309  //SanitizeDuplicates cleans out all duplicates
   310  func SanitizeDuplicates(b []string) []string {
   311  	sz := len(b) - 1
   312  	for i := 0; i < sz; i++ {
   313  		for j := i + 1; j <= sz; j++ {
   314  			if (b)[i] == ((b)[j]) {
   315  				(b)[j] = (b)[sz]
   316  				(b) = (b)[0:sz]
   317  				sz--
   318  				j--
   319  			}
   320  		}
   321  	}
   322  	return b
   323  }
   324  
   325  // GetPackageDir returns the directory of a package path from the go src dir.
   326  func GetPackageDir(pkgname string) (string, error) {
   327  	pkg, err := build.Import(pkgname, "", 0)
   328  
   329  	if err != nil {
   330  		return "", err
   331  	}
   332  
   333  	return pkg.Dir, nil
   334  }
   335  
   336  // GetPackageLists retrieves a packages  directory and those of its dependencies
   337  func GetPackageLists(pkgname string) ([]string, error) {
   338  	var paths []string
   339  	var err error
   340  
   341  	if paths, err = getPackageLists(pkgname, paths); err != nil {
   342  		return nil, err
   343  	}
   344  
   345  	return SanitizeDuplicates(paths), nil
   346  }
   347  
   348  // GetAllPackageLists retrieves a set of packages directory and those of its dependencies
   349  func GetAllPackageLists(pkgnames []string) ([]string, error) {
   350  	var packages []string
   351  	var err error
   352  
   353  	for _, pkg := range pkgnames {
   354  		if packages, err = getPackageLists(pkg, packages); err != nil {
   355  			return nil, err
   356  		}
   357  	}
   358  
   359  	// log.Printf("Packages: %s", packages)
   360  	return SanitizeDuplicates(packages), nil
   361  }
   362  
   363  // getPackageLists returns the lists of internal package imports used within
   364  // a giving package.
   365  func getPackageLists(pkgname string, paths []string) ([]string, error) {
   366  	pkg, err := build.Import(pkgname, "", 0)
   367  
   368  	if err != nil {
   369  		return nil, err
   370  	}
   371  
   372  	if pkg.Goroot {
   373  		return paths, nil
   374  	}
   375  
   376  	paths = append(paths, pkg.Dir)
   377  
   378  	for _, imp := range pkg.Imports {
   379  		if p, err := getPackageLists(imp, paths); err == nil {
   380  			paths = p
   381  		} else {
   382  			return nil, err
   383  		}
   384  	}
   385  
   386  	return paths, nil
   387  }