Add sample-complex.
diff --git a/logger.go b/logger.go
index 0c478be..b70a799 100644
--- a/logger.go
+++ b/logger.go
@@ -7,8 +7,70 @@
import (
"io/ioutil"
"log"
+ "fmt"
+ "io"
+ "log"
+ "os"
)
+// Logger defines a reduced interface that covers most of what the standard
+// package log exposes in a more coherent way.
+//
+// The author of this code thinks Fatal*(), Panic*() and *ln() are highly
+// redundants so they were not implemented.
+type Logger interface {
+ Flags() int
+ Prefix() string
+ Print(v ...interface{})
+ Printf(format string, v ...interface{})
+ SetFlags(flag int)
+ SetOutput(w io.Writer)
+ SetPrefix(prefix string)
+}
+
+type privateLoggerImpl struct {
+ l *log.Logger
+}
+
+// NewLogger returns a Logger instead with the current settings and output set
+// to os.Stderr.
+func NewLogger() Logger {
+ return &privateLoggerImpl{log.New(os.Stderr, log.Prefix(), log.Flags())}
+}
+
+// NewPrivateLogger converts a log.Logger into a Logger interface.
+func NewPrivateLogger(l *log.Logger) Logger {
+ return &privateLoggerImpl{l}
+}
+
+func (l *privateLoggerImpl) Flags() int {
+ return l.l.Flags()
+}
+
+func (l *privateLoggerImpl) Prefix() string {
+ return l.l.Prefix()
+}
+
+func (l *privateLoggerImpl) Print(v ...interface{}) {
+ l.l.Output(2, fmt.Sprint(v...))
+}
+
+func (l *privateLoggerImpl) Printf(format string, v ...interface{}) {
+ l.l.Output(2, fmt.Sprintf(format, v...))
+}
+
+func (l *privateLoggerImpl) SetFlags(flag int) {
+ l.l.SetFlags(flag)
+}
+
+func (l *privateLoggerImpl) SetOutput(w io.Writer) {
+ l.l = log.New(w, l.l.Prefix(), l.l.Flags())
+}
+
+func (l *privateLoggerImpl) SetPrefix(prefix string) {
+ l.l.SetPrefix(prefix)
+}
+
// PanicWriter is an io.Writer that will panic if used.
type PanicWriter struct {
}
diff --git a/sample-complex/main.go b/sample-complex/main.go
index 05078d5..b346adc 100644
--- a/sample-complex/main.go
+++ b/sample-complex/main.go
@@ -6,12 +6,10 @@
package main
import (
- "io/ioutil"
"log"
"os"
"github.com/maruel/subcommands"
- "github.com/maruel/subcommands/subcommandstest"
)
var application = &subcommands.DefaultApplication{
@@ -40,9 +38,7 @@
}
type sampleApplication interface {
- // TODO(maruel): This is wrong, subcommandtest should only be referenced in
- // unit tests. Figure out a way to better plug logging.
- subcommandstest.Application
+ subcommands.Application
// Add anything desired, in particular if you'd like to crete a fake
// application during testing.
@@ -50,16 +46,27 @@
type sample struct {
*subcommands.DefaultApplication
- log *log.Logger
-}
-
-// GetLog implements subcommandstest.Application.
-func (s *sample) GetLog() *log.Logger {
- return s.log
}
func main() {
subcommands.KillStdLog()
- s := &sample{application, log.New(ioutil.Discard, "", log.LstdFlags|log.Lmicroseconds)}
- os.Exit(subcommands.Run(s, nil))
+ application := &subcommands.DefaultApplication{
+ Logger: subcommands.NewLogger(),
+ Name: "sample",
+ Title: "Sample tool to act as a skeleton for subcommands usage.",
+ // Commands will be shown in this exact order, so you'll likely want to put
+ // them in alphabetical order or in logical grouping.
+ Commands: []*subcommands.Command{
+ cmdGreet,
+ subcommands.CmdHelp,
+ cmdAsk,
+ cmdSleep,
+ },
+ }
+
+ application.SetFlags(log.LstdFlags | log.Lmicroseconds)
+ // Disable log by default, unless -verbose is specified.
+ //d := &sample{application, log.New(nullWriter(0), "", log.LstdFlags|log.Lmicroseconds)}
+ d := &sample{application, log.New(application.GetErr(), "")}
+ os.Exit(subcommands.Run(d, nil))
}
diff --git a/sample-simple/main.go b/sample-simple/main.go
index 02d0aa5..c38a33f 100644
--- a/sample-simple/main.go
+++ b/sample-simple/main.go
@@ -83,6 +83,7 @@
}
func main() {
+ // It is not used Application.Logger.
log.SetFlags(log.Lmicroseconds)
os.Exit(subcommands.Run(application, nil))
}
diff --git a/subcommands.go b/subcommands.go
index e25eef7..0d68936 100644
--- a/subcommands.go
+++ b/subcommands.go
@@ -25,6 +25,8 @@
// Application describes an application with subcommand support.
type Application interface {
+ Logger
+
// GetName returns the 'name' of the application.
GetName() string
@@ -58,7 +60,12 @@
// DefaultApplication implements all of Application interface's methods. An
// application should usually have a global instance of DefaultApplication and
// route main() to command_support.Run(app).
+//
+// DefaultApplication doesn't mock os.Stdout and os.Stderr.
type DefaultApplication struct {
+ // It is recommended to use NewLogger() to initialize this value.
+ Logger
+
Name string
Title string
Commands []*Command
@@ -262,6 +269,7 @@
return c
}
}
+ // TODO(maruel): Try fuzzy matching.
return nil
}
diff --git a/subcommandstest/subcommandstest.go b/subcommandstest/subcommandstest.go
index 669cbac..d3ef3ba 100644
--- a/subcommandstest/subcommandstest.go
+++ b/subcommandstest/subcommandstest.go
@@ -102,18 +102,6 @@
t.log = log.New(os.Stderr, "", log.Lmicroseconds)
}
-// GetLog implements Application.
-func (t *TB) GetLog() *log.Logger {
- return t.log
-}
-
-// Application supports all of subcommands.Application and adds GetLog() for
-// testing purposes.
-type Application interface {
- subcommands.Application
- GetLog() *log.Logger
-}
-
// ApplicationMock wrap both an Application and a TB. ApplicationMock
// implements GetOut and GetErr and adds GetLog(). GetLog() is implemented by
// TB.