176 lines
4.2 KiB
Go
176 lines
4.2 KiB
Go
/*
|
|
* @Descripation: mvn解析依赖树
|
|
* @Date: 2021-12-16 10:10:13
|
|
*/
|
|
|
|
package java
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/tls"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
"util/args"
|
|
"util/cache"
|
|
"util/enum/language"
|
|
"util/logs"
|
|
"util/model"
|
|
"util/temp"
|
|
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// MvnDepTree 调用mvn解析项目获取依赖树
|
|
func MvnDepTree(path string, root *model.DepTree) {
|
|
pwd := temp.GetPwd()
|
|
os.Chdir(path)
|
|
cmd := exec.Command("mvn", "dependency:tree", "--fail-never")
|
|
out, _ := cmd.CombinedOutput()
|
|
os.Chdir(pwd)
|
|
// 统一替换换行符为\n
|
|
out = bytes.ReplaceAll(out, []byte("\r\n"), []byte("\n"))
|
|
out = bytes.ReplaceAll(out, []byte("\n\r"), []byte("\n"))
|
|
out = bytes.ReplaceAll(out, []byte("\r"), []byte("\n"))
|
|
// 获取mvn解析内容
|
|
lines := strings.Split(string(out), "\n")
|
|
for i := range lines {
|
|
lines[i] = strings.TrimPrefix(lines[i], "[INFO] ")
|
|
}
|
|
// 捕获依赖树起始位置
|
|
title := regexp.MustCompile(`--- [^\n]+ ---`)
|
|
// 记录依赖树起始位置行号
|
|
start := 0
|
|
// 标记是否在依赖范围内树
|
|
tree := false
|
|
root.Direct = true
|
|
// 获取mvn依赖树
|
|
for i, line := range lines {
|
|
if title.MatchString(line) {
|
|
tree = true
|
|
start = i
|
|
continue
|
|
}
|
|
if tree && strings.Trim(line, "-") == "" {
|
|
tree = false
|
|
buildMvnDepTree(root, lines[start+1:i])
|
|
for _, c := range root.Children {
|
|
c.Direct = true
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// buildMvnDepTree 构建mvn树
|
|
func buildMvnDepTree(root *model.DepTree, lines []string) {
|
|
// 记录当前的顶点节点列表
|
|
tops := []*model.DepTree{root}
|
|
// 上一层级
|
|
lastLevel := -1
|
|
for _, line := range lines {
|
|
// 计算层级
|
|
level := 0
|
|
for line[level*3+2] == ' ' {
|
|
level++
|
|
}
|
|
tops = tops[:len(tops)-lastLevel+level-1]
|
|
root = tops[len(tops)-1]
|
|
tags := strings.Split(line[level*3:], ":")
|
|
if len(tags) < 4 {
|
|
logs.Error(errors.New("mvn parse error"))
|
|
break
|
|
}
|
|
dep := model.NewDepTree(root)
|
|
dep.Vendor = tags[0]
|
|
dep.Name = tags[1]
|
|
dep.Version = model.NewVersion(tags[3])
|
|
dep.Language = language.Java
|
|
tops = append(tops, dep)
|
|
lastLevel = level
|
|
}
|
|
}
|
|
|
|
// downloadPom 下载pom文件
|
|
func downloadPom(dep model.Dependency) (data []byte, err error) {
|
|
tags := strings.Split(dep.Vendor, ".")
|
|
tags = append(tags, dep.Name)
|
|
tags = append(tags, dep.Version.Org)
|
|
tags = append(tags, fmt.Sprintf("%s-%s.pom", dep.Name, dep.Version.Org))
|
|
// 先扫描指定仓库
|
|
for _, m := range args.Config.Maven {
|
|
url := strings.TrimSuffix(m.Repo, `/`) + `/`
|
|
url = url + strings.Join(tags, "/")
|
|
name := m.User
|
|
password := m.Password
|
|
data, err = getFromRepo(url, name, password)
|
|
if data == nil {
|
|
continue
|
|
}
|
|
return
|
|
}
|
|
// 指定仓库都没有就去官方仓库查询
|
|
d := `https://repo.maven.apache.org/maven2/`
|
|
url := d + strings.Join(tags, "/")
|
|
if rep, err := http.Get(url); err != nil {
|
|
return nil, err
|
|
} else {
|
|
defer rep.Body.Close()
|
|
if rep.StatusCode == 200 {
|
|
return ioutil.ReadAll(rep.Body)
|
|
}
|
|
}
|
|
// 应该走不到这里
|
|
return nil, fmt.Errorf("download failure")
|
|
}
|
|
|
|
// 从私服库获取pom文件
|
|
func getFromRepo(url string, name string, password string) (data []byte, err error) {
|
|
c := http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, Timeout: time.Duration(1 * time.Second)}
|
|
resp, err := c.Get(url)
|
|
if err != nil {
|
|
return nil, err
|
|
} else {
|
|
resp.Request.SetBasicAuth(name, password)
|
|
defer resp.Body.Close()
|
|
logs.Debug(fmt.Sprintf("status code: %d url: %s", resp.StatusCode, url))
|
|
if resp.StatusCode == 200 {
|
|
return ioutil.ReadAll(resp.Body)
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("download from repository failure")
|
|
}
|
|
|
|
// getpom is get pom from index
|
|
func getpom(groupId, artifactId, version string) (p *Pom) {
|
|
p = &Pom{Properties: PomProperties{}}
|
|
if groupId == "" || artifactId == "" || version == "" {
|
|
return nil
|
|
}
|
|
dep := model.Dependency{
|
|
Vendor: groupId,
|
|
Name: artifactId,
|
|
Version: model.NewVersion(version),
|
|
}
|
|
data := cache.LoadCache(dep)
|
|
if len(data) != 0 {
|
|
return ReadPom(data)
|
|
} else {
|
|
// 无本地缓存下载pom文件
|
|
if data, err := downloadPom(dep); err == nil {
|
|
// 保存pom文件
|
|
cache.SaveCache(dep, data)
|
|
return ReadPom(data)
|
|
} else {
|
|
logs.Warn(err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|