mirror of https://github.com/perkeep/perkeep.git
devcam fixv,hook: docs, bugfix, cleanup.
Change-Id: Ie5f9f9ea62c13221d6b9c9913ef953ab39fb7914
This commit is contained in:
parent
c9027c2c7f
commit
9a24acca6c
|
@ -26,6 +26,7 @@ import (
|
|||
"os/signal"
|
||||
pathpkg "path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
@ -153,9 +154,9 @@ func handleSignals(camliProc *os.Process) {
|
|||
func checkCamliSrcRoot() {
|
||||
args := flag.Args()
|
||||
// TODO(mpl): we should probably get rid of that limitation someday.
|
||||
if len(args) > 0 && args[0] == "review" ||
|
||||
if len(args) > 0 && (args[0] == "review" ||
|
||||
args[0] == "hook" ||
|
||||
args[0] == "fixv" {
|
||||
args[0] == "fixv") {
|
||||
// exception for devcam review, which does its own check.
|
||||
return
|
||||
}
|
||||
|
@ -172,6 +173,26 @@ func checkCamliSrcRoot() {
|
|||
camliSrcRoot = cwd
|
||||
}
|
||||
|
||||
func repoRoot() (string, error) {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not get current directory: %v", err)
|
||||
}
|
||||
rootlen := 1
|
||||
if runtime.GOOS == "windows" {
|
||||
rootlen += len(filepath.VolumeName(dir))
|
||||
}
|
||||
for {
|
||||
if _, err := os.Stat(filepath.Join(dir, ".git")); err == nil {
|
||||
return dir, nil
|
||||
}
|
||||
if len(dir) == rootlen && dir[rootlen-1] == filepath.Separator {
|
||||
return "", fmt.Errorf(".git not found. Rerun from within the Camlistore source tree.")
|
||||
}
|
||||
dir = filepath.Dir(dir)
|
||||
}
|
||||
}
|
||||
|
||||
func selfModTime() (time.Time, error) {
|
||||
var modTime time.Time
|
||||
devcamBin, err := osutil.SelfPath()
|
||||
|
|
|
@ -59,7 +59,18 @@ func init() {
|
|||
}
|
||||
|
||||
func (c *fixvCmd) Usage() {
|
||||
fmt.Fprintf(cmdmain.Stderr, "Usage: devcam [globalopts] fixv [args...]\n")
|
||||
cmdmain.Errorf("Usage: devcam [globalopts] fixv [args...]\n")
|
||||
}
|
||||
|
||||
func (c *fixvCmd) Describe() string {
|
||||
return "Check, and optionally fix, import statements in vendored files."
|
||||
}
|
||||
|
||||
func (c *fixvCmd) Examples() []string {
|
||||
return []string{
|
||||
"-w # automatically fix the imports in the vendored files from the git staging area",
|
||||
"/foo/bar.go # assume /foo/bar.go is vendored, and check if it needs to have its import fixed",
|
||||
}
|
||||
}
|
||||
|
||||
func (c *fixvCmd) RunCommand(args []string) error {
|
||||
|
@ -72,12 +83,19 @@ func (c *fixvCmd) run(args []string) (tofix []string, err error) {
|
|||
if len(args) != 0 {
|
||||
vendoredFiles = args
|
||||
} else {
|
||||
repo := repoRoot()
|
||||
repo, err := repoRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !strings.HasSuffix(repo, string(filepath.Separator)) {
|
||||
repo += string(filepath.Separator)
|
||||
}
|
||||
|
||||
vendoredFiles = addRoot(repo, filter(isVendored, nonBlankLines(cmdOutput("git", "diff-index", "--name-only", "--diff-filter=ACM", "--cached", "HEAD", "--"))))
|
||||
out, err := cmdOutputDirErr(".", "git", "diff-index", "--name-only", "--diff-filter=ACM", "--cached", "HEAD", "--")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vendoredFiles = addRoot(repo, filter(isVendored, nonBlankLines(out)))
|
||||
if len(vendoredFiles) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -92,7 +110,7 @@ func (c *fixvCmd) run(args []string) (tofix []string, err error) {
|
|||
continue
|
||||
}
|
||||
if !c.fix {
|
||||
fmt.Fprintf(cmdmain.Stderr, "%v imports need fixing\n", filename)
|
||||
cmdmain.Errorf("%v imports need fixing\n", filename)
|
||||
tofix = append(tofix, filename)
|
||||
continue
|
||||
}
|
||||
|
@ -103,7 +121,7 @@ func (c *fixvCmd) run(args []string) (tofix []string, err error) {
|
|||
if err := ioutil.WriteFile(filename, data, 0600); err != nil {
|
||||
return nil, fmt.Errorf("failed to write modified file %v: %v", filename, err)
|
||||
}
|
||||
fmt.Fprintf(cmdmain.Stderr, "%v imports now fixed\n", filename)
|
||||
cmdmain.Errorf("%v imports now fixed\n", filename)
|
||||
}
|
||||
if !c.fix && len(tofix) > 0 {
|
||||
return tofix, errImportsNeedsFixing
|
||||
|
|
|
@ -26,7 +26,6 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
|
@ -39,8 +38,12 @@ var hookFiles = []string{
|
|||
}
|
||||
|
||||
func (c *hookCmd) installHook() error {
|
||||
root, err := repoRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, hookFile := range hookFiles {
|
||||
filename := filepath.Join(repoRoot(), hookPath+hookFile)
|
||||
filename := filepath.Join(root, hookPath+hookFile)
|
||||
hookContent := fmt.Sprintf(hookScript, hookFile)
|
||||
// If hook file exists, assume it is okay.
|
||||
_, err := os.Stat(filename)
|
||||
|
@ -73,27 +76,32 @@ exec devcam hook %s "$@"
|
|||
|
||||
type hookCmd struct {
|
||||
verbose bool
|
||||
fix bool // disabled for now
|
||||
debug bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmdmain.RegisterCommand("hook", func(flags *flag.FlagSet) cmdmain.CommandRunner {
|
||||
cmd := &hookCmd{}
|
||||
flags.BoolVar(&cmd.verbose, "verbose", false, "Be verbose.")
|
||||
flags.BoolVar(&cmd.debug, "debug", false, "Arguments after the hook name are files that will be used as input to the hook, instead of the hook using the staging area.")
|
||||
// TODO(mpl): "-w" flag to run gofmt -w and devcam fixv -w. for now just print instruction.
|
||||
// flags.BoolVar(&cmd.fix, "w", false, "Perform appropriate fixes, for hooks like pre-commit.")
|
||||
return cmd
|
||||
})
|
||||
}
|
||||
|
||||
// TODO(mpl): more docs, examples. Also doc in website to tell ppl to use it.
|
||||
|
||||
func (c *hookCmd) Usage() {
|
||||
printf("Usage: devcam [globalopts] hook [[hook-name] [args...]]\n")
|
||||
}
|
||||
|
||||
func (c *hookCmd) Examples() []string {
|
||||
return []string{
|
||||
"# install the hooks (if needed)",
|
||||
"pre-commit # install the hooks (if needed), then run the pre-commit hook",
|
||||
}
|
||||
}
|
||||
|
||||
func (c *hookCmd) Describe() string {
|
||||
return "Install git hooks for Camlistore, and if given, run the hook given as argument. Currently available hooks are: " + strings.TrimSuffix(strings.Join(hookFiles, ", "), ",") + "."
|
||||
}
|
||||
|
||||
func (c *hookCmd) RunCommand(args []string) error {
|
||||
if err := c.installHook(); err != nil {
|
||||
return err
|
||||
|
@ -105,9 +113,8 @@ func (c *hookCmd) RunCommand(args []string) error {
|
|||
case "pre-commit":
|
||||
if err := c.hookPreCommit(args[1:]); err != nil {
|
||||
printf("You can override these checks with 'git commit --no-verify'\n")
|
||||
// TODO(mpl): make sure that by exiting "early" we're not skipping some post-RunCommand
|
||||
// stuff controlled by cmdmain.Main
|
||||
os.Exit(1)
|
||||
cmdmain.ExitWithFailure = true
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -140,7 +147,7 @@ func (c *hookCmd) hookGofmt() error {
|
|||
|
||||
files, err := c.runGofmt()
|
||||
if err != nil {
|
||||
printf("gofmt reported errors:\n\t%v\n", strings.Replace(strings.TrimSpace(err.Error()), "\n", "\n\t", -1))
|
||||
printf("gofmt hook reported errors:\n\t%v\n", strings.Replace(strings.TrimSpace(err.Error()), "\n", "\n\t", -1))
|
||||
return errors.New("gofmt errors")
|
||||
}
|
||||
if len(files) == 0 {
|
||||
|
@ -167,7 +174,7 @@ func (c *hookCmd) hookTrailingSpace() error {
|
|||
func (c *hookCmd) hookVendoredImports(args []string) error {
|
||||
tofix, err := (&fixvCmd{
|
||||
verbose: c.verbose,
|
||||
fix: c.fix,
|
||||
fix: false,
|
||||
}).run(args)
|
||||
if err != nil {
|
||||
if err == errImportsNeedsFixing {
|
||||
|
@ -183,12 +190,19 @@ func (c *hookCmd) hookVendoredImports(args []string) error {
|
|||
// runGofmt runs the external gofmt command over the local version of staged files.
|
||||
// It returns the files that need gofmting.
|
||||
func (c *hookCmd) runGofmt() (files []string, err error) {
|
||||
repo := repoRoot()
|
||||
repo, err := repoRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !strings.HasSuffix(repo, string(filepath.Separator)) {
|
||||
repo += string(filepath.Separator)
|
||||
}
|
||||
|
||||
indexFiles := addRoot(repo, filter(gofmtRequired, nonBlankLines(cmdOutput("git", "diff-index", "--name-only", "--diff-filter=ACM", "--cached", "HEAD", "--"))))
|
||||
out, err := cmdOutputDirErr(".", "git", "diff-index", "--name-only", "--diff-filter=ACM", "--cached", "HEAD", "--")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indexFiles := addRoot(repo, filter(gofmtRequired, nonBlankLines(out)))
|
||||
if len(indexFiles) == 0 {
|
||||
return
|
||||
}
|
||||
|
@ -225,32 +239,7 @@ func (c *hookCmd) runGofmt() (files []string, err error) {
|
|||
}
|
||||
|
||||
func printf(format string, args ...interface{}) {
|
||||
fmt.Fprintf(cmdmain.Stderr, format, args...)
|
||||
}
|
||||
|
||||
func dief(format string, args ...interface{}) {
|
||||
printf(format, args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func repoRoot() string {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
dief("could not get current directory: %v", err)
|
||||
}
|
||||
rootlen := 1
|
||||
if runtime.GOOS == "windows" {
|
||||
rootlen += len(filepath.VolumeName(dir))
|
||||
}
|
||||
for {
|
||||
if _, err := os.Stat(filepath.Join(dir, ".git")); err == nil {
|
||||
return dir
|
||||
}
|
||||
if len(dir) == rootlen && dir[rootlen-1] == filepath.Separator {
|
||||
dief(".git not found. Rerun from within the Camlistore source tree.")
|
||||
}
|
||||
dir = filepath.Dir(dir)
|
||||
}
|
||||
cmdmain.Errorf(format, args...)
|
||||
}
|
||||
|
||||
func addRoot(root string, list []string) []string {
|
||||
|
@ -315,23 +304,6 @@ func (c *hookCmd) verbosef(format string, args ...interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
// cmdOutput runs the command line, returning its output.
|
||||
// If the command cannot be run or does not exit successfully,
|
||||
// cmdOutput dies.
|
||||
//
|
||||
// NOTE: cmdOutput must be used only to run commands that read state,
|
||||
// not for commands that make changes. Commands that make changes
|
||||
// should be run using runDirErr so that the -v and -n flags apply to them.
|
||||
func cmdOutput(command string, args ...string) string {
|
||||
out, err := cmdOutputDirErr(".", command, args...)
|
||||
if err != nil {
|
||||
printf("%v\n", err)
|
||||
// TODO(mpl): maybe not die. see other comment about cmdmain.Main.
|
||||
os.Exit(1)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// cmdOutputDirErr runs the command line in dir, returning its output
|
||||
// and any error results.
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue