2016-11-04 01:16:01 +03:00
// Copyright 2015 The Gogs Authors. All rights reserved.
2019-06-07 23:29:29 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2016-11-04 01:16:01 +03:00
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package git
import (
"container/list"
"fmt"
2018-01-07 16:10:20 +03:00
"io"
2016-11-04 01:16:01 +03:00
"strconv"
"strings"
"time"
2019-06-12 22:41:28 +03:00
logger "code.gitea.io/gitea/modules/log"
2016-11-04 01:16:01 +03:00
)
2019-06-07 23:29:29 +03:00
// CompareInfo represents needed information for comparing references.
type CompareInfo struct {
2016-11-04 01:16:01 +03:00
MergeBase string
Commits * list . List
NumFiles int
}
2019-06-12 02:32:08 +03:00
// GetMergeBase checks and returns merge base of two branches and the reference used as base.
func ( repo * Repository ) GetMergeBase ( tmpRemote string , base , head string ) ( string , string , error ) {
2019-06-07 23:29:29 +03:00
if tmpRemote == "" {
tmpRemote = "origin"
}
if tmpRemote != "origin" {
tmpBaseName := "refs/remotes/" + tmpRemote + "/tmp_" + base
// Fetch commit into a temporary branch in order to be able to handle commits and tags
_ , err := NewCommand ( "fetch" , tmpRemote , base + ":" + tmpBaseName ) . RunInDir ( repo . Path )
if err == nil {
base = tmpBaseName
}
}
2019-08-05 23:39:39 +03:00
stdout , err := NewCommand ( "merge-base" , "--" , base , head ) . RunInDir ( repo . Path )
2019-06-12 02:32:08 +03:00
return strings . TrimSpace ( stdout ) , base , err
2016-11-04 01:16:01 +03:00
}
2019-06-07 23:29:29 +03:00
// GetCompareInfo generates and returns compare information between base and head branches of repositories.
func ( repo * Repository ) GetCompareInfo ( basePath , baseBranch , headBranch string ) ( _ * CompareInfo , err error ) {
var (
remoteBranch string
tmpRemote string
)
2016-11-04 01:16:01 +03:00
// We don't need a temporary remote for same repository.
if repo . Path != basePath {
// Add a temporary remote
2019-06-07 23:29:29 +03:00
tmpRemote = strconv . FormatInt ( time . Now ( ) . UnixNano ( ) , 10 )
2019-08-13 11:30:44 +03:00
if err = repo . AddRemote ( tmpRemote , basePath , false ) ; err != nil {
2016-11-04 01:16:01 +03:00
return nil , fmt . Errorf ( "AddRemote: %v" , err )
}
2019-06-12 22:41:28 +03:00
defer func ( ) {
if err := repo . RemoveRemote ( tmpRemote ) ; err != nil {
logger . Error ( "GetPullRequestInfo: RemoveRemote: %v" , err )
}
} ( )
2016-11-04 01:16:01 +03:00
}
2019-06-07 23:29:29 +03:00
compareInfo := new ( CompareInfo )
2019-06-12 02:32:08 +03:00
compareInfo . MergeBase , remoteBranch , err = repo . GetMergeBase ( tmpRemote , baseBranch , headBranch )
2019-04-09 23:45:58 +03:00
if err == nil {
// We have a common base
2019-06-07 23:29:29 +03:00
logs , err := NewCommand ( "log" , compareInfo . MergeBase + "..." + headBranch , prettyLogFormat ) . RunInDirBytes ( repo . Path )
2019-04-09 23:45:58 +03:00
if err != nil {
return nil , err
}
2019-06-07 23:29:29 +03:00
compareInfo . Commits , err = repo . parsePrettyFormatLogToList ( logs )
2019-04-09 23:45:58 +03:00
if err != nil {
return nil , fmt . Errorf ( "parsePrettyFormatLogToList: %v" , err )
}
} else {
2019-06-07 23:29:29 +03:00
compareInfo . Commits = list . New ( )
compareInfo . MergeBase , err = GetFullCommitID ( repo . Path , remoteBranch )
2019-04-09 23:45:58 +03:00
if err != nil {
2019-06-07 23:29:29 +03:00
compareInfo . MergeBase = remoteBranch
2019-04-09 23:45:58 +03:00
}
2016-11-04 01:16:01 +03:00
}
// Count number of changed files.
stdout , err := NewCommand ( "diff" , "--name-only" , remoteBranch + "..." + headBranch ) . RunInDir ( repo . Path )
if err != nil {
return nil , err
}
2019-06-07 23:29:29 +03:00
compareInfo . NumFiles = len ( strings . Split ( stdout , "\n" ) ) - 1
2016-11-04 01:16:01 +03:00
2019-06-07 23:29:29 +03:00
return compareInfo , nil
2016-11-04 01:16:01 +03:00
}
2019-12-14 01:21:06 +03:00
// GetDiffOrPatch generates either diff or formatted patch data between given revisions
func ( repo * Repository ) GetDiffOrPatch ( base , head string , w io . Writer , formatted bool ) error {
if formatted {
return repo . GetPatch ( base , head , w )
}
return repo . GetDiff ( base , head , w )
2016-11-04 01:16:01 +03:00
}
2018-01-07 16:10:20 +03:00
2019-12-14 01:21:06 +03:00
// GetDiff generates and returns patch data between given revisions.
func ( repo * Repository ) GetDiff ( base , head string , w io . Writer ) error {
return NewCommand ( "diff" , "-p" , "--binary" , base , head ) .
RunInDirPipeline ( repo . Path , w , nil )
}
2018-01-07 16:10:20 +03:00
2019-12-14 01:21:06 +03:00
// GetPatch generates and returns format-patch data between given revisions.
func ( repo * Repository ) GetPatch ( base , head string , w io . Writer ) error {
return NewCommand ( "format-patch" , "--binary" , "--stdout" , base + "..." + head ) .
RunInDirPipeline ( repo . Path , w , nil )
2018-01-07 16:10:20 +03:00
}
2020-01-09 04:47:45 +03:00
// GetDiffFromMergeBase generates and return patch data from merge base to head
func ( repo * Repository ) GetDiffFromMergeBase ( base , head string , w io . Writer ) error {
return NewCommand ( "diff" , "-p" , "--binary" , base + "..." + head ) .
RunInDirPipeline ( repo . Path , w , nil )
}