2019-04-30 07:02:09 +03:00
package git
import (
"log"
"os"
"os/exec"
"path/filepath"
"strings"
2019-08-19 11:47:18 +03:00
"github.com/aquasecurity/vuln-list-update/utils"
2019-04-30 07:02:09 +03:00
"golang.org/x/xerrors"
)
2019-10-08 03:28:23 +03:00
type Operations interface {
2020-12-17 18:05:35 +03:00
CloneOrPull ( string , string , string ) ( map [ string ] struct { } , error )
2019-10-08 03:28:23 +03:00
RemoteBranch ( string ) ( [ ] string , error )
Checkout ( string , string ) error
}
type Config struct {
}
2021-01-17 07:31:52 +03:00
func ( gc Config ) CloneOrPull ( url , repoPath , branch string , debug bool ) ( map [ string ] struct { } , error ) {
2019-04-30 07:02:09 +03:00
exists , err := utils . Exists ( filepath . Join ( repoPath , ".git" ) )
if err != nil {
return nil , err
}
updatedFiles := map [ string ] struct { } { }
if exists {
2021-01-17 07:31:52 +03:00
if debug {
log . Println ( "Skip git pull" )
return nil , nil
}
2019-04-30 07:02:09 +03:00
log . Println ( "git pull" )
2020-12-17 18:05:35 +03:00
files , err := pull ( url , repoPath , branch )
2019-04-30 07:02:09 +03:00
if err != nil {
return nil , xerrors . Errorf ( "git pull error: %w" , err )
}
for _ , filename := range files {
updatedFiles [ strings . TrimSpace ( filename ) ] = struct { } { }
}
} else {
if err = os . MkdirAll ( repoPath , 0700 ) ; err != nil {
return nil , err
}
2021-04-27 13:59:59 +03:00
if err := clone ( url , repoPath , branch ) ; err != nil {
2019-04-30 07:02:09 +03:00
return nil , err
}
2020-04-06 12:57:24 +03:00
if err := fetchAll ( repoPath ) ; err != nil {
return nil , err
}
2019-04-30 07:02:09 +03:00
err = filepath . Walk ( repoPath , func ( path string , info os . FileInfo , err error ) error {
if info . IsDir ( ) {
return nil
}
updatedFiles [ path ] = struct { } { }
return nil
} )
if err != nil {
return nil , err
}
}
return updatedFiles , nil
}
2021-04-27 13:59:59 +03:00
func clone ( url , repoPath , branch string ) error {
2023-06-22 10:20:19 +03:00
commandAndArgs := [ ] string {
"clone" ,
"--depth" ,
"1" ,
url ,
repoPath ,
}
2021-04-27 13:59:59 +03:00
if branch != "" {
commandAndArgs = append ( commandAndArgs , "-b" , branch )
}
2019-04-30 07:02:09 +03:00
cmd := exec . Command ( "git" , commandAndArgs ... )
cmd . Stdout = os . Stdout
cmd . Stderr = os . Stderr
if err := cmd . Run ( ) ; err != nil {
return xerrors . Errorf ( "failed to clone: %w" , err )
}
return nil
}
2020-12-17 18:05:35 +03:00
func pull ( url , repoPath , branch string ) ( [ ] string , error ) {
2019-04-30 07:02:09 +03:00
commandArgs := generateGitArgs ( repoPath )
2023-06-22 10:20:19 +03:00
remoteCmd := [ ] string {
"remote" ,
"get-url" ,
"--push" ,
"origin" ,
}
2019-10-02 11:05:57 +03:00
output , err := utils . Exec ( "git" , append ( commandArgs , remoteCmd ... ) )
2019-04-30 07:02:09 +03:00
if err != nil {
2019-10-02 11:05:57 +03:00
return nil , xerrors . Errorf ( "error in git rev-list: %w" , err )
}
remoteURL := strings . TrimSpace ( output )
if remoteURL != url {
return nil , xerrors . Errorf ( "remote url is %s, target is %s" , remoteURL , url )
}
2023-06-22 10:20:19 +03:00
revParseCmd := [ ] string {
"rev-list" ,
"-n" ,
"1" ,
"--all" ,
}
2019-10-02 11:05:57 +03:00
output , err = utils . Exec ( "git" , append ( commandArgs , revParseCmd ... ) )
if err != nil {
return nil , xerrors . Errorf ( "error in git rev-list: %w" , err )
2019-04-30 07:02:09 +03:00
}
commitHash := strings . TrimSpace ( output )
2019-10-02 11:05:57 +03:00
if len ( commitHash ) == 0 {
log . Println ( "no commit yet" )
return nil , nil
}
2019-04-30 07:02:09 +03:00
2023-06-22 10:20:19 +03:00
pullCmd := [ ] string {
"pull" ,
"origin" ,
}
2021-04-27 13:59:59 +03:00
if branch != "" {
pullCmd = append ( pullCmd , branch )
}
2019-04-30 07:02:09 +03:00
if _ , err = utils . Exec ( "git" , append ( commandArgs , pullCmd ... ) ) ; err != nil {
return nil , xerrors . Errorf ( "error in git pull: %w" , err )
}
2023-06-22 10:20:19 +03:00
fetchCmd := [ ] string {
"fetch" ,
"--prune" ,
}
2019-04-30 07:02:09 +03:00
if _ , err = utils . Exec ( "git" , append ( commandArgs , fetchCmd ... ) ) ; err != nil {
return nil , xerrors . Errorf ( "error in git fetch: %w" , err )
}
2023-06-22 10:20:19 +03:00
diffCmd := [ ] string {
"diff" ,
commitHash ,
"HEAD" ,
"--name-only" ,
}
2019-04-30 07:02:09 +03:00
output , err = utils . Exec ( "git" , append ( commandArgs , diffCmd ... ) )
if err != nil {
return nil , err
}
updatedFiles := strings . Split ( strings . TrimSpace ( output ) , "\n" )
return updatedFiles , nil
}
2020-04-06 12:57:24 +03:00
func fetchAll ( repoPath string ) error {
commandArgs := generateGitArgs ( repoPath )
2023-06-22 10:20:19 +03:00
configCmd := [ ] string {
"config" ,
"remote.origin.fetch" ,
"+refs/heads/*:refs/remotes/origin/*" ,
}
2020-04-06 12:57:24 +03:00
if _ , err := utils . Exec ( "git" , append ( commandArgs , configCmd ... ) ) ; err != nil {
return xerrors . Errorf ( "error in git config: %w" , err )
}
2023-06-22 10:20:19 +03:00
fetchCmd := [ ] string {
"fetch" ,
"--all" ,
}
2020-04-06 12:57:24 +03:00
if _ , err := utils . Exec ( "git" , append ( commandArgs , fetchCmd ... ) ) ; err != nil {
return xerrors . Errorf ( "error in git fetch: %w" , err )
}
return nil
}
2019-04-30 07:02:09 +03:00
func generateGitArgs ( repoPath string ) [ ] string {
gitDir := filepath . Join ( repoPath , ".git" )
2023-06-22 10:20:19 +03:00
return [ ] string {
"--git-dir" ,
gitDir ,
"--work-tree" ,
repoPath ,
}
2022-01-16 19:44:06 +03:00
}