Skip to content

Commit 36058d7

Browse files
authored
Merge pull request #158 from vmarkovtsev/master
Add "path" command line arguments
2 parents bdc9bc2 + 8e3e241 commit 36058d7

File tree

11 files changed

+132
-18
lines changed

11 files changed

+132
-18
lines changed

cmd/hercules/root.go

+46-11
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ func loadPlugins() {
147147
const pluginDesc = "Load the specified plugin by the full or relative path. " +
148148
"Can be specified multiple times."
149149
fs.Var(&pluginFlags, pluginFlagName, pluginDesc)
150+
err := cobra.MarkFlagFilename(fs, "plugin")
151+
if err != nil {
152+
panic(err)
153+
}
150154
pflag.Var(&pluginFlags, pluginFlagName, pluginDesc)
151155
fs.Parse(os.Args[1:])
152156
for path := range pluginFlags {
@@ -168,17 +172,39 @@ targets can be added using the --plugin system.`,
168172
Args: cobra.RangeArgs(1, 2),
169173
Run: func(cmd *cobra.Command, args []string) {
170174
flags := cmd.Flags()
171-
firstParent, _ := flags.GetBool("first-parent")
172-
commitsFile, _ := flags.GetString("commits")
173-
protobuf, _ := flags.GetBool("pb")
174-
profile, _ := flags.GetBool("profile")
175-
disableStatus, _ := flags.GetBool("quiet")
176-
sshIdentity, _ := flags.GetString("ssh-identity")
175+
getBool := func(name string) bool {
176+
value, err := flags.GetBool(name)
177+
if err != nil {
178+
panic(err)
179+
}
180+
return value
181+
}
182+
getString := func(name string) string {
183+
value, err := flags.GetString(name)
184+
if err != nil {
185+
panic(err)
186+
}
187+
return value
188+
}
189+
firstParent := getBool("first-parent")
190+
commitsFile := getString("commits")
191+
protobuf := getBool("pb")
192+
profile := getBool("profile")
193+
disableStatus := getBool("quiet")
194+
sshIdentity := getString("ssh-identity")
177195

178196
if profile {
179-
go http.ListenAndServe("localhost:6060", nil)
197+
go func() {
198+
err := http.ListenAndServe("localhost:6060", nil)
199+
if err != nil {
200+
panic(err)
201+
}
202+
}()
180203
prof, _ := os.Create("hercules.pprof")
181-
pprof.StartCPUProfile(prof)
204+
err := pprof.StartCPUProfile(prof)
205+
if err != nil {
206+
panic(err)
207+
}
182208
defer pprof.StopCPUProfile()
183209
}
184210
uri := args[0]
@@ -350,6 +376,7 @@ func formatUsage(c *cobra.Command) error {
350376
leaves := hercules.Registry.GetLeaves()
351377
plumbing := hercules.Registry.GetPlumbingItems()
352378
features := hercules.Registry.GetFeaturedItems()
379+
hercules.EnablePathFlagTypeMasquerade()
353380
filter := map[string]bool{}
354381
for _, l := range leaves {
355382
filter[l.Flag()] = true
@@ -450,20 +477,28 @@ var cmdlineDeployed map[string]*bool
450477

451478
func init() {
452479
loadPlugins()
453-
rootCmd.MarkFlagFilename("plugin")
454480
rootFlags := rootCmd.Flags()
455481
rootFlags.String("commits", "", "Path to the text file with the "+
456-
"commit history to follow instead of the default `git log`. "+
482+
"commit history to follow instead of the default 'git log'. "+
457483
"The format is the list of hashes, each hash on a "+
458484
"separate line. The first hash is the root.")
459-
rootCmd.MarkFlagFilename("commits")
485+
err := rootCmd.MarkFlagFilename("commits")
486+
if err != nil {
487+
panic(err)
488+
}
489+
hercules.PathifyFlagValue(rootFlags.Lookup("commits"))
460490
rootFlags.Bool("first-parent", false, "Follow only the first parent in the commit history - "+
461491
"\"git log --first-parent\".")
462492
rootFlags.Bool("pb", false, "The output format will be Protocol Buffers instead of YAML.")
463493
rootFlags.Bool("quiet", !terminal.IsTerminal(int(os.Stdin.Fd())),
464494
"Do not print status updates to stderr.")
465495
rootFlags.Bool("profile", false, "Collect the profile to hercules.pprof.")
466496
rootFlags.String("ssh-identity", "", "Path to SSH identity file (e.g., ~/.ssh/id_rsa) to clone from an SSH remote.")
497+
err = rootCmd.MarkFlagFilename("ssh-identity")
498+
if err != nil {
499+
panic(err)
500+
}
501+
hercules.PathifyFlagValue(rootFlags.Lookup("ssh-identity"))
467502
cmdlineFacts, cmdlineDeployed = hercules.Registry.AddFlags(rootFlags)
468503
rootCmd.SetUsageFunc(formatUsage)
469504
rootCmd.AddCommand(versionCmd)

core.go

+12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package hercules
22

33
import (
4+
"github.com/spf13/pflag"
45
"gopkg.in/src-d/go-git.v4"
56
"gopkg.in/src-d/go-git.v4/plumbing/object"
67
"gopkg.in/src-d/hercules.v6/internal/core"
@@ -158,6 +159,17 @@ func SafeYamlString(str string) string {
158159
return yaml.SafeString(str)
159160
}
160161

162+
// PathifyFlagValue changes the type of a string command line argument to "path".
163+
func PathifyFlagValue(flag *pflag.Flag) {
164+
core.PathifyFlagValue(flag)
165+
}
166+
167+
// EnablePathFlagTypeMasquerade changes the type of all "path" command line arguments from "string"
168+
// to "path". This operation cannot be canceled and is intended to be used for better --help output.
169+
func EnablePathFlagTypeMasquerade() {
170+
core.EnablePathFlagTypeMasquerade()
171+
}
172+
161173
func init() {
162174
// hack to link with .leaves
163175
_ = leaves.BurndownAnalysis{}

internal/core/pipeline.go

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ const (
3636
FloatConfigurationOption
3737
// StringsConfigurationOption reflects the array of strings value type.
3838
StringsConfigurationOption
39+
// PathConfigurationOption reflects the file system path value type.
40+
PathConfigurationOption
3941
)
4042

4143
// String() returns an empty string for the boolean type, "int" for integers and "string" for
@@ -52,6 +54,8 @@ func (opt ConfigurationOptionType) String() string {
5254
return "float"
5355
case StringsConfigurationOption:
5456
return "string"
57+
case PathConfigurationOption:
58+
return "path"
5559
}
5660
log.Panicf("Invalid ConfigurationOptionType value %d", opt)
5761
return ""

internal/core/pipeline_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,8 @@ func TestConfigurationOptionTypeString(t *testing.T) {
584584
opt = ConfigurationOptionType(4)
585585
assert.Equal(t, opt.String(), "string")
586586
opt = ConfigurationOptionType(5)
587+
assert.Equal(t, opt.String(), "path")
588+
opt = ConfigurationOptionType(6)
587589
assert.Panics(t, func() { _ = opt.String() })
588590
}
589591

internal/core/registry.go

+46-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"strings"
88
"unsafe"
99

10+
"github.com/spf13/cobra"
1011
"github.com/spf13/pflag"
1112
)
1213

@@ -39,7 +40,7 @@ func (registry *PipelineItemRegistry) Register(example PipelineItem) {
3940
// the specified string. It materializes all the found types and returns them.
4041
func (registry *PipelineItemRegistry) Summon(providesOrName string) []PipelineItem {
4142
if registry.provided == nil {
42-
return []PipelineItem{}
43+
return nil
4344
}
4445
ts := registry.provided[providesOrName]
4546
var items []PipelineItem
@@ -120,6 +121,41 @@ func (registry *PipelineItemRegistry) GetFeaturedItems() map[string][]FeaturedPi
120121
return features
121122
}
122123

124+
var pathFlagTypeMasquerade bool
125+
126+
// EnablePathFlagTypeMasquerade changes the type of all "path" command line arguments from "string"
127+
// to "path". This operation cannot be canceled and is intended to be used for better --help output.
128+
func EnablePathFlagTypeMasquerade() {
129+
pathFlagTypeMasquerade = true
130+
}
131+
132+
type pathValue struct {
133+
origin pflag.Value
134+
}
135+
136+
func wrapPathValue(val pflag.Value) pflag.Value {
137+
return &pathValue{val}
138+
}
139+
140+
func (s *pathValue) Set(val string) error {
141+
return s.origin.Set(val)
142+
}
143+
func (s *pathValue) Type() string {
144+
if pathFlagTypeMasquerade {
145+
return "path"
146+
}
147+
return "string"
148+
}
149+
150+
func (s *pathValue) String() string {
151+
return s.origin.String()
152+
}
153+
154+
// PathifyFlagValue changes the type of a string command line argument to "path".
155+
func PathifyFlagValue(flag *pflag.Flag) {
156+
flag.Value = wrapPathValue(flag.Value)
157+
}
158+
123159
type arrayFeatureFlags struct {
124160
// Flags contains the features activated through the command line.
125161
Flags []string
@@ -172,10 +208,17 @@ func (registry *PipelineItemRegistry) AddFlags(flagSet *pflag.FlagSet) (
172208
iface = interface{}(0)
173209
ptr := (**int)(getPtr())
174210
*ptr = flagSet.Int(opt.Flag, opt.Default.(int), formatHelp(opt.Description))
175-
case StringConfigurationOption:
211+
case StringConfigurationOption, PathConfigurationOption:
176212
iface = interface{}("")
177213
ptr := (**string)(getPtr())
178214
*ptr = flagSet.String(opt.Flag, opt.Default.(string), formatHelp(opt.Description))
215+
if opt.Type == PathConfigurationOption {
216+
err := cobra.MarkFlagFilename(flagSet, opt.Flag)
217+
if err != nil {
218+
panic(err)
219+
}
220+
PathifyFlagValue(flagSet.Lookup(opt.Flag))
221+
}
179222
case FloatConfigurationOption:
180223
iface = interface{}(float32(0))
181224
ptr := (**float32)(getPtr())
@@ -203,6 +246,7 @@ func (registry *PipelineItemRegistry) AddFlags(flagSet *pflag.FlagSet) (
203246
ptr1 := (**string)(unsafe.Pointer(uintptr(unsafe.Pointer(&iface)) + unsafe.Sizeof(&iface)))
204247
*ptr1 = flagSet.String("dump-dag", "", "Write the pipeline DAG to a Graphviz file.")
205248
flags[ConfigPipelineDAGPath] = iface
249+
PathifyFlagValue(flagSet.Lookup("dump-dag"))
206250
iface = interface{}(true)
207251
ptr2 := (**bool)(unsafe.Pointer(uintptr(unsafe.Pointer(&iface)) + unsafe.Sizeof(&iface)))
208252
*ptr2 = flagSet.Bool("dry-run", false, "Do not run any analyses - only resolve the DAG. "+

internal/core/registry_test.go

+17
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package core
22

33
import (
4+
"os"
45
"reflect"
56
"testing"
67

78
"github.com/spf13/cobra"
9+
"github.com/spf13/pflag"
810
"github.com/stretchr/testify/assert"
911
"gopkg.in/src-d/go-git.v4"
1012
"gopkg.in/src-d/hercules.v6/internal/test"
@@ -114,6 +116,7 @@ func (item *dummyPipelineItem2) Merge(branches []PipelineItem) {
114116

115117
func TestRegistrySummon(t *testing.T) {
116118
reg := getRegistry()
119+
assert.Len(t, reg.Summon("whatever"), 0)
117120
reg.Register(&testPipelineItem{})
118121
summoned := reg.Summon((&testPipelineItem{}).Provides()[0])
119122
assert.Len(t, summoned, 1)
@@ -215,3 +218,17 @@ func TestRegistryFeaturedItems(t *testing.T) {
215218
assert.Equal(t, featured["power"][0].Name(), (&testPipelineItem{}).Name())
216219
assert.Equal(t, featured["power"][1].Name(), (&dummyPipelineItem{}).Name())
217220
}
221+
222+
func TestRegistryPathMasquerade(t *testing.T) {
223+
fs := pflag.NewFlagSet(os.Args[0], pflag.ContinueOnError)
224+
var value string
225+
fs.StringVar(&value, "test", "", "usage")
226+
flag := fs.Lookup("test")
227+
PathifyFlagValue(flag)
228+
assert.Equal(t, flag.Value.Type(), "string")
229+
assert.Nil(t, flag.Value.Set("xxx"))
230+
assert.Equal(t, flag.Value.String(), "xxx")
231+
EnablePathFlagTypeMasquerade()
232+
assert.Equal(t, flag.Value.Type(), "path")
233+
assert.Equal(t, flag.Value.String(), "xxx")
234+
}

internal/plumbing/identity/identity.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func (detector *Detector) ListConfigurationOptions() []core.ConfigurationOption
7676
Name: ConfigIdentityDetectorPeopleDictPath,
7777
Description: "Path to the file with developer -> name|email associations.",
7878
Flag: "people-dict",
79-
Type: core.StringConfigurationOption,
79+
Type: core.PathConfigurationOption,
8080
Default: ""},
8181
}
8282
return options[:]

internal/plumbing/uast/uast.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ func (saver *ChangesSaver) ListConfigurationOptions() []core.ConfigurationOption
460460
Name: ConfigUASTChangesSaverOutputPath,
461461
Description: "The target directory where to store the changed UAST files.",
462462
Flag: "changed-uast-dir",
463-
Type: core.StringConfigurationOption,
463+
Type: core.PathConfigurationOption,
464464
Default: "."},
465465
}
466466
return options[:]

leaves/burndown.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ func (analyser *BurndownAnalysis) ListConfigurationOptions() []core.Configuratio
229229
Description: "Temporary directory where to save the hibernated RBTree allocators; " +
230230
"requires --burndown-hibernation-disk.",
231231
Flag: "burndown-hibernation-dir",
232-
Type: core.StringConfigurationOption,
232+
Type: core.PathConfigurationOption,
233233
Default: ""}, {
234234
Name: ConfigBurndownDebug,
235235
Description: "Validate the trees on each step.",

leaves/devs.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func (devs *DevsAnalysis) ListConfigurationOptions() []core.ConfigurationOption
8888
options := [...]core.ConfigurationOption{{
8989
Name: ConfigDevsConsiderEmptyCommits,
9090
Description: "Take into account empty commits such as trivial merges.",
91-
Flag: "--empty-commits",
91+
Flag: "empty-commits",
9292
Type: core.BoolConfigurationOption,
9393
Default: false}}
9494
return options[:]

leaves/devs_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func TestDevsMeta(t *testing.T) {
3737
assert.Equal(t, d.Flag(), "devs")
3838
assert.Len(t, d.ListConfigurationOptions(), 1)
3939
assert.Equal(t, d.ListConfigurationOptions()[0].Name, ConfigDevsConsiderEmptyCommits)
40-
assert.Equal(t, d.ListConfigurationOptions()[0].Flag, "--empty-commits")
40+
assert.Equal(t, d.ListConfigurationOptions()[0].Flag, "empty-commits")
4141
assert.Equal(t, d.ListConfigurationOptions()[0].Type, core.BoolConfigurationOption)
4242
assert.Equal(t, d.ListConfigurationOptions()[0].Default, false)
4343
assert.True(t, len(d.Description()) > 0)

0 commit comments

Comments
 (0)