Prechádzať zdrojové kódy

Merge pull request #184 from vmarkovtsev/master

Fix huge renames
Vadim Markovtsev 6 rokov pred
rodič
commit
1f4363c18c

+ 22 - 17
internal/core/forks.go

@@ -161,28 +161,33 @@ func prepareRunPlan(commits []*object.Commit, hibernationDistance int,
 	}
 	if printResult {
 		for _, p := range plan {
-			firstItem := p.Items[0]
-			switch p.Action {
-			case runActionCommit:
-				planPrintFunc("C", firstItem, p.Commit.Hash.String())
-			case runActionFork:
-				planPrintFunc("F", p.Items)
-			case runActionMerge:
-				planPrintFunc("M", p.Items)
-			case runActionEmerge:
-				planPrintFunc("E", p.Items)
-			case runActionDelete:
-				planPrintFunc("D", p.Items)
-			case runActionHibernate:
-				planPrintFunc("H", firstItem)
-			case runActionBoot:
-				planPrintFunc("B", firstItem)
-			}
+			printAction(p)
 		}
 	}
 	return plan
 }
 
+// printAction prints the specified action to stderr.
+func printAction(p runAction) {
+	firstItem := p.Items[0]
+	switch p.Action {
+	case runActionCommit:
+		planPrintFunc("C", firstItem, p.Commit.Hash.String())
+	case runActionFork:
+		planPrintFunc("F", p.Items)
+	case runActionMerge:
+		planPrintFunc("M", p.Items)
+	case runActionEmerge:
+		planPrintFunc("E", p.Items)
+	case runActionDelete:
+		planPrintFunc("D", p.Items)
+	case runActionHibernate:
+		planPrintFunc("H", firstItem)
+	case runActionBoot:
+		planPrintFunc("B", firstItem)
+	}
+}
+
 // buildDag generates the raw commit DAG and the commit hash map.
 func buildDag(commits []*object.Commit) (
 	map[string]*object.Commit, map[plumbing.Hash][]*object.Commit) {

+ 11 - 0
internal/core/pipeline.go

@@ -258,6 +258,9 @@ type Pipeline struct {
 	// DumpPlan indicates whether to print the execution plan to stderr.
 	DumpPlan bool
 
+	// PrintActions indicates whether to print the taken actions during the execution.
+	PrintActions bool
+
 	// Repository points to the analysed Git repository struct from go-git.
 	repository *git.Repository
 
@@ -291,6 +294,9 @@ const (
 	// which is the minimum number of actions between two sequential usages of
 	// a branch to activate the hibernation optimization (cpu-memory trade-off). 0 disables.
 	ConfigPipelineHibernationDistance = "Pipeline.HibernationDistance"
+	// ConfigPipelinePrintActions is the name of the Pipeline configuration option (Pipeline.Initialize())
+	// which enables printing the taken actions of the execution plan to stderr.
+	ConfigPipelinePrintActions = "Pipeline.PrintActions"
 	// DependencyCommit is the name of one of the three items in `deps` supplied to PipelineItem.Consume()
 	// which always exists. It corresponds to the currently analyzed commit.
 	DependencyCommit = "commit"
@@ -630,6 +636,7 @@ func (pipeline *Pipeline) Initialize(facts map[string]interface{}) error {
 			log.Panicf("failed to list the commits: %v", err)
 		}
 	}
+	pipeline.PrintActions, _ = facts[ConfigPipelinePrintActions].(bool)
 	if val, exists := facts[ConfigPipelineHibernationDistance].(int); exists {
 		if val < 0 {
 			log.Panicf("--hibernation-distance cannot be negative (got %d)", val)
@@ -727,6 +734,10 @@ func (pipeline *Pipeline) Run(commits []*object.Commit) (map[LeafPipelineItem]in
 		if pipeline.DryRun {
 			continue
 		}
+		if pipeline.PrintActions {
+			fmt.Fprintln(os.Stderr)
+			printAction(step)
+		}
 		if index > 0 && index%100 == 0 && pipeline.HibernationDistance > 0 {
 			debug.FreeOSMemory()
 		}

+ 1 - 0
internal/core/pipeline_test.go

@@ -852,6 +852,7 @@ func TestPipelineRunHibernation(t *testing.T) {
 			t.Fatal(err)
 		}
 	}
+	pipeline.PrintActions = true
 	_, err := pipeline.Run(commits)
 	assert.Nil(t, err)
 	assert.True(t, item.Hibernated)

+ 4 - 0
internal/core/registry.go

@@ -262,6 +262,10 @@ func (registry *PipelineItemRegistry) AddFlags(flagSet *pflag.FlagSet) (
 			"Minimum number of actions between two sequential usages of a branch to activate "+
 				"the hibernation optimization (cpu-memory trade-off). 0 disables.")
 		flags[ConfigPipelineHibernationDistance] = iface
+		iface = interface{}(true)
+		ptr5 := (**bool)(unsafe.Pointer(uintptr(unsafe.Pointer(&iface)) + unsafe.Sizeof(&iface)))
+		*ptr5 = flagSet.Bool("print-actions", false, "Print the executed actions to stderr.")
+		flags[ConfigPipelinePrintActions] = iface
 	}
 	var features []string
 	for f := range registry.featureFlags.Choices {

+ 2 - 1
internal/core/registry_test.go

@@ -138,7 +138,7 @@ func TestRegistryAddFlags(t *testing.T) {
 		Run:   func(cmd *cobra.Command, args []string) {},
 	}
 	facts, deployed := reg.AddFlags(testCmd.Flags())
-	assert.Len(t, facts, 6)
+	assert.Len(t, facts, 7)
 	assert.IsType(t, 0, facts[(&testPipelineItem{}).ListConfigurationOptions()[0].Name])
 	assert.IsType(t, true, facts[(&dummyPipelineItem{}).ListConfigurationOptions()[0].Name])
 	assert.Contains(t, facts, ConfigPipelineDryRun)
@@ -153,6 +153,7 @@ func TestRegistryAddFlags(t *testing.T) {
 	assert.NotNil(t, testCmd.Flags().Lookup("dump-plan"))
 	assert.NotNil(t, testCmd.Flags().Lookup("dry-run"))
 	assert.NotNil(t, testCmd.Flags().Lookup("hibernation-distance"))
+	assert.NotNil(t, testCmd.Flags().Lookup("print-actions"))
 	assert.NotNil(t, testCmd.Flags().Lookup(
 		(&testPipelineItem{}).ListConfigurationOptions()[0].Flag))
 	assert.NotNil(t, testCmd.Flags().Lookup(

+ 10 - 2
internal/plumbing/renames.go

@@ -44,6 +44,10 @@ const (
 
 	// RenameAnalysisMaxCandidates is the maximum number of rename candidates to consider per file.
 	RenameAnalysisMaxCandidates = 50
+
+	// RenameAnalysisSetSizeLimit is the maximum number of added + removed files for
+	// RenameAnalysisMaxCandidates to be active; the bigger numbers set it to 1.
+	RenameAnalysisSetSizeLimit = 1000
 )
 
 // Name of this PipelineItem. Uniquely identifies the type, used for mapping keys, etc.
@@ -163,6 +167,10 @@ func (ra *RenameAnalysis) Consume(deps map[string]interface{}) (map[string]inter
 	// Stage 2 - apply the similarity threshold
 	// n^2 but actually linear
 	// We sort the blobs by size and do the single linear scan.
+	maxCandidates := RenameAnalysisMaxCandidates
+	if len(stillAdded)+len(stillDeleted) > RenameAnalysisSetSizeLimit {
+		maxCandidates = 1
+	}
 	addedBlobs := make(sortableBlobs, 0, stillAdded.Len())
 	deletedBlobs := make(sortableBlobs, 0, stillDeleted.Len())
 	var smallChanges []*object.Change
@@ -226,7 +234,7 @@ func (ra *RenameAnalysis) Consume(deps map[string]interface{}) (map[string]inter
 				if finished {
 					return nil
 				}
-				if ci > RenameAnalysisMaxCandidates {
+				if ci > maxCandidates {
 					break
 				}
 				blobsAreClose, err := ra.blobsAreClose(
@@ -281,7 +289,7 @@ func (ra *RenameAnalysis) Consume(deps map[string]interface{}) (map[string]inter
 				if finished {
 					return nil
 				}
-				if ci > RenameAnalysisMaxCandidates {
+				if ci > maxCandidates {
 					break
 				}
 				blobsAreClose, err := ra.blobsAreClose(