The file strategies have all been settled on, including the ability
to detect when a repository is un-lint-able (due to merge conflicts in the current tree munging up source files). 250 lines of hand- written Hy, and I haven't even gotten to the main part of the project, actually running the linters.
This commit is contained in:
parent
caed12257f
commit
0ec3a446ba
|
@ -284,3 +284,4 @@
|
||||||
(let [[empty-repository-hash "4b825dc642cb6eb9a060e54bf8d69288fbee4904"]
|
(let [[empty-repository-hash "4b825dc642cb6eb9a060e54bf8d69288fbee4904"]
|
||||||
[(, out err returncode) (get-git-response ["rev-parse" "--verify HEAD"])]]
|
[(, out err returncode) (get-git-response ["rev-parse" "--verify HEAD"])]]
|
||||||
(if err empty-repository-hash "HEAD")))
|
(if err empty-repository-hash "HEAD")))
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
(def *version* "0.0.2")
|
(def *version* "0.0.2")
|
||||||
|
|
||||||
(defn tap [a] (print "TAP:" a) a)
|
(defn tap [a] (print "TAP:" a) a)
|
||||||
|
|
||||||
; short-name long-name takes-args description precludes
|
; short-name long-name takes-args description precludes
|
||||||
(def optlist [["o" "only" true (_ "A comma-separated list of only those linters to run") ["exclude"]]
|
(def optlist [["o" "only" true (_ "A comma-separated list of only those linters to run") ["exclude"]]
|
||||||
["x" "exclude" true (_ "A comma-separated list of linters to skip") []]
|
["x" "exclude" true (_ "A comma-separated list of linters to skip") []]
|
||||||
|
@ -60,56 +59,13 @@
|
||||||
(get-git-response-raw ["rev-parse" "--show-toplevel"])]]
|
(get-git-response-raw ["rev-parse" "--show-toplevel"])]]
|
||||||
(if (not (= returncode 0)) None (.rstrip out))))
|
(if (not (= returncode 0)) None (.rstrip out))))
|
||||||
|
|
||||||
(defn get-all-from-cwd []
|
; That mystery number is the precise hash code for a repository for has been initialized,
|
||||||
(split-git-response ["ls-tree" "--name-only" "-r" "HEAD"]))
|
; but for which nothing has ever been added or committed. An empty repository has no refs
|
||||||
|
; at all so you can't use HEAD in this one very rare case.
|
||||||
(defn get-all-from-base []
|
(def git-head
|
||||||
(split-git-response ["ls-tree" "--name-only" "-r" "--full-tree" "HEAD"]))
|
(let [[empty-repository-hash "4b825dc642cb6eb9a060e54bf8d69288fbee4904"]
|
||||||
|
[(, out err returncode) (get-git-response-raw ["rev-parse" "--verify HEAD"])]]
|
||||||
; Any of these indicate the tree is in a merge
|
(if (not err) "HEAD" empty-repository-hash)))
|
||||||
; conflict state and the user has bigger problems.
|
|
||||||
(def *merge-conflict-pairs* (set ["DD" "DU" "AU" "AA" "UD" "UA" "UU"]))
|
|
||||||
(defn get-changed-from-source [trackings]
|
|
||||||
(let [[conflicts (filter (fn [t] (t[0:2] in *merge-conflict-pairs*)) trackings)]]
|
|
||||||
(if (len conflicts)
|
|
||||||
(sys.exit (_ "Current repository contains merge conflicts. Linters will not be run."))
|
|
||||||
trackings)))
|
|
||||||
|
|
||||||
(defn get-porcelain-status [cmd]
|
|
||||||
(let [[stream (.split (get-git-response cmd) "\0")]
|
|
||||||
[parse-stream (fn [acc stream]
|
|
||||||
(if (= 0 (len stream))
|
|
||||||
acc
|
|
||||||
(let [[temp (.pop stream 0)]
|
|
||||||
[index (.pop temp 0)]
|
|
||||||
[workspace (.pop temp 0)]
|
|
||||||
[filename (slice temp 1)]]
|
|
||||||
(if (= index "R")
|
|
||||||
(.pop stream 0))
|
|
||||||
(parse-stream (.append acc (, index workspace filename)) stream))))]]
|
|
||||||
(parse-stream [] stream)))
|
|
||||||
|
|
||||||
(defn modified-in-workspace [s] (s[0] in ["M" "A" "?"]))
|
|
||||||
(defn modified-in-staging [s] (s[1] in ["M" "A" "?"]))
|
|
||||||
(defn get-name [s] (s[2]))
|
|
||||||
|
|
||||||
;(defn get-changed-from-cwd []
|
|
||||||
; (->> (get-changed-from_source (split-git-response ["status" "--porcelain" "--untracked-files=all"]))
|
|
||||||
; (filter (fn [s] (s[0] in
|
|
||||||
;
|
|
||||||
; (map (fn [s]
|
|
||||||
; (filter (fn [s] (
|
|
||||||
;
|
|
||||||
|
|
||||||
(defn get-changed-from-base []
|
|
||||||
(get-changed-from_source (split-git-response ["status" "--porcelain" "--untracked-files=all" git-base])))
|
|
||||||
|
|
||||||
(defn get-staged-from-cwd []
|
|
||||||
())
|
|
||||||
|
|
||||||
(defn gen-staged-from-base []
|
|
||||||
())
|
|
||||||
|
|
||||||
|
|
||||||
(defn make-match-filter-matcher [extensions]
|
(defn make-match-filter-matcher [extensions]
|
||||||
(->> (map (fn [s] (.split s ",")) extensions)
|
(->> (map (fn [s] (.split s ",")) extensions)
|
||||||
|
@ -125,7 +81,13 @@
|
||||||
(defn make-match-filter [config]
|
(defn make-match-filter [config]
|
||||||
(let [[matcher (make-match-filter-matcher (map (fn [v] (.get v "match" "" ))
|
(let [[matcher (make-match-filter-matcher (map (fn [v] (.get v "match" "" ))
|
||||||
(.itervalues config)))]]
|
(.itervalues config)))]]
|
||||||
(fn [path] (.search matcher path))))
|
(fn [path] (print matcher.pattern) (.search matcher path))))
|
||||||
|
|
||||||
|
; _ _ _ _ _ _ _ _
|
||||||
|
;| | (_)_ _| |_ ___ _ _ _____ _____ __ _ _| |_ __ _| |__| |___ __| |_ __ _| |_ _ _ ___
|
||||||
|
;| |__| | ' \ _/ -_) '_| / -_) \ / -_) _| || | _/ _` | '_ \ / -_) (_-< _/ _` | _| || (_-<
|
||||||
|
;|____|_|_||_\__\___|_| \___/_\_\___\__|\_,_|\__\__,_|_.__/_\___| /__/\__\__,_|\__|\_,_/__/
|
||||||
|
;
|
||||||
|
|
||||||
(defn executable-exists [script label]
|
(defn executable-exists [script label]
|
||||||
(if (not (len script))
|
(if (not (len script))
|
||||||
|
@ -149,27 +111,141 @@
|
||||||
(print (.format "{:<14} {}" linter (_ "(WARNING: executable not found)")))
|
(print (.format "{:<14} {}" linter (_ "(WARNING: executable not found)")))
|
||||||
(print (.format "{:<14} {}" linter (.get items "comment" ""))))))
|
(print (.format "{:<14} {}" linter (.get items "comment" ""))))))
|
||||||
|
|
||||||
(defn git-lint-main [options]
|
; ___ _ _ _ _ __ _ _ _
|
||||||
(print git-base)
|
;| __(_) |___ _ __ __ _| |_| |_ / _(_) | |_ ___ _ _ ___
|
||||||
(print (os.path.abspath __file__))
|
;| _|| | / -_) | '_ \/ _` | _| ' \ | _| | | _/ -_) '_(_-<
|
||||||
(let [[config (get-config-file options git-base)]]
|
;|_| |_|_\___| | .__/\__,_|\__|_||_| |_| |_|_|\__\___|_| /__/
|
||||||
(print options)
|
; |_|
|
||||||
(print config)
|
|
||||||
(print (make-match-filter config))))
|
(defn remove-submodules [files]
|
||||||
|
(let [[split-out-paths (fn [s] (get (.split s " ") 2))]
|
||||||
|
[fixer-re (re.compile "^(\.\.\/)+")]
|
||||||
|
[fixer-to-base (fn [s] (.sub fixer-re "" s))]
|
||||||
|
[submodule-entries (split-git-response ["submodule" "status"])]
|
||||||
|
[submodule-names (map (fn [s] (fixer-to-base (split-out-paths s))) submodule-entries)]]
|
||||||
|
(filter (fn [s] (not (in s submodule-names))) files)))
|
||||||
|
|
||||||
|
(defn base-file-filter [files]
|
||||||
|
(map (fn [f] (os.path.join git-base f)) files))
|
||||||
|
|
||||||
|
(defn cwd-file-filter [files]
|
||||||
|
(let [[gitcwd (os.path.join (os.path.relpath (os.getcwd) git-base) "")]]
|
||||||
|
(base-file-filter (filter (fn [f] (.startswith f gitcwd)) files))))
|
||||||
|
|
||||||
|
(defn base-file-cleaner [files]
|
||||||
|
(map (fn [f] (.replace f git-base 1)) files))
|
||||||
|
|
||||||
|
; ___ __ _ _ _ _ _ _
|
||||||
|
;| _ \__ ___ __ __ / _(_) |___ | (_)__| |_ __ _ ___ _ _ ___ _ _ __ _| |_ ___ _ _ ___
|
||||||
|
;| / _` \ V V / | _| | / -_) | | (_-< _| / _` / -_) ' \/ -_) '_/ _` | _/ _ \ '_(_-<
|
||||||
|
;|_|_\__,_|\_/\_/ |_| |_|_\___| |_|_/__/\__| \__, \___|_||_\___|_| \__,_|\__\___/_| /__/
|
||||||
|
; |___/
|
||||||
|
|
||||||
|
(def *merge-conflict-pairs* (set ["DD" "DU" "AU" "AA" "UD" "UA" "UU"]))
|
||||||
|
(defn check-for-conflicts [files]
|
||||||
|
(let [[status-pairs (map (fn [(, index workspace filename)] (+ "" index workspace)) files)]
|
||||||
|
[conflicts (& (set *merge-conflict-pairs*) (set status-pairs))]]
|
||||||
|
(if (len conflicts)
|
||||||
|
(sys.exit (_ "Current repository contains merge conflicts. Linters will not be run."))
|
||||||
|
files)))
|
||||||
|
|
||||||
|
(defn get-porcelain-status []
|
||||||
|
(let [[cmd ["status" "-z" "--porcelain" "--untracked-files=all" "--ignore-submodules=all"]]
|
||||||
|
[nonnull (fn [s] (> (len s) 0))]
|
||||||
|
[stream (list (filter nonnull (.split (get-git-response cmd) "\0")))]
|
||||||
|
[parse-stream (fn [acc stream]
|
||||||
|
(if (= 0 (len stream))
|
||||||
|
acc
|
||||||
|
(let [[temp (.pop stream 0)]
|
||||||
|
[index (get temp 0)]
|
||||||
|
[workspace (get temp 1)]
|
||||||
|
[filename (slice temp 3)]]
|
||||||
|
(if (= index "R")
|
||||||
|
(.pop stream 0))
|
||||||
|
(parse-stream (+ acc [(, index workspace filename)]) stream))))]]
|
||||||
|
(check-for-conflicts (parse-stream [] stream))))
|
||||||
|
|
||||||
|
(defn staging-list []
|
||||||
|
(map (fn [(, index workspace filename)] filename)
|
||||||
|
(filter (fn [(, index workspace filename)] (in index ["A" "M"])) (get-porcelain-status))))
|
||||||
|
|
||||||
|
(defn working-list []
|
||||||
|
(map (fn [(, index workspace filename)] filename)
|
||||||
|
(filter (fn [(, index workspace filename)] (in workspace ["A" "M" "?"])) (get-porcelain-status))))
|
||||||
|
|
||||||
|
(defn all-list []
|
||||||
|
(let [[cmd ["ls-tree" "--name-only" "--full-tree" "-r" "-z" git-head]]]
|
||||||
|
(filter (fn [s] (> (len s) 0)) (.split (get-git-response cmd) "\0"))))
|
||||||
|
|
||||||
|
; _ _ _ __ _ _ _ _ _ _
|
||||||
|
; /_\ ______ ___ _ __ | |__| |___ / _(_) |___ | (_)__| |_ __ _ ___ _ _ ___ _ _ __ _| |_ ___ _ _
|
||||||
|
; / _ \ (_-<_-</ -_) ' \| '_ \ / -_) | _| | / -_) | | (_-< _| / _` / -_) ' \/ -_) '_/ _` | _/ _ \ '_|
|
||||||
|
;/_/ \_\/__/__/\___|_|_|_|_.__/_\___| |_| |_|_\___| |_|_/__/\__| \__, \___|_||_\___|_| \__,_|\__\___/_|
|
||||||
|
; |___/
|
||||||
|
|
||||||
|
(defn pick-filelist-strategy [options]
|
||||||
|
(let [[keys (.keys options)]
|
||||||
|
[working-directory-trans (if (len (& (set keys) (set ["base" "every"]))) base-file-filter cwd-file-filter)]
|
||||||
|
[file-list-generator (cond [(in "staging" keys) staging-list]
|
||||||
|
[(in "all" keys) all-list]
|
||||||
|
[true working-list])]]
|
||||||
|
(fn [] (working-directory-trans (remove-submodules (file-list-generator))))))
|
||||||
|
|
||||||
|
; ___ _
|
||||||
|
; / __| |_ ___ ___ ___ ___ __ _ _ _ _ _ _ _ _ _ ___ _ _
|
||||||
|
;| (__| ' \/ _ \/ _ (_-</ -_) / _` | | '_| || | ' \| ' \/ -_) '_|
|
||||||
|
; \___|_||_\___/\___/__/\___| \__,_| |_| \_,_|_||_|_||_\___|_|
|
||||||
|
;
|
||||||
|
|
||||||
|
(defn staging-wrapper [run-linters]
|
||||||
|
(let [[time-gather (fn [f] (let [[stats (os.stat f)]]
|
||||||
|
(, f (, stats.atime stats.mtime))))]
|
||||||
|
[times (list (map time-gather files))]]
|
||||||
|
(run-git-command ["stash" "--keep-index"])
|
||||||
|
(let [[results (run-linters)]]
|
||||||
|
(run-git-command ["reset" "--hard"])
|
||||||
|
(run-git-command ["stash" "pop" "--quiet" "--index"])
|
||||||
|
(for [(, filename timepair) times]
|
||||||
|
(os.utime filename timepair))
|
||||||
|
results)))
|
||||||
|
|
||||||
|
(defn workspace-wrapper [run-linters]
|
||||||
|
(run-linters files))
|
||||||
|
|
||||||
|
(defn pick-runner [options]
|
||||||
|
(let [[keys (.keys options)]]
|
||||||
|
(if (in "s" keys) staging-wrapper workspace-wrapper)))
|
||||||
|
|
||||||
|
; __ __ _
|
||||||
|
;| \/ |__ _(_)_ _
|
||||||
|
;| |\/| / _` | | ' \
|
||||||
|
;|_| |_\__,_|_|_||_|
|
||||||
|
;
|
||||||
|
|
||||||
|
(defn run-gitlint [options config extras]
|
||||||
|
(let [[file-lister (pick-filelist-strategy options)]
|
||||||
|
[runner (pick-runner options)]
|
||||||
|
[match-filter (make-match-filter config)]
|
||||||
|
[lintables (set (filter match-filter (file-lister)))]
|
||||||
|
|
||||||
|
; [report-maker (pick-report-maker options)]
|
||||||
|
; [linters (pick-linters options config)]]
|
||||||
|
]
|
||||||
|
(print (list lintables))))
|
||||||
|
|
||||||
(defmain [&rest args]
|
(defmain [&rest args]
|
||||||
(if (= git-base None)
|
|
||||||
(sys<.exit (_ "Not currently in a git repository."))
|
|
||||||
(try
|
|
||||||
(let [[opts (hyopt optlist args "git lint"
|
(let [[opts (hyopt optlist args "git lint"
|
||||||
"Copyright (c) 2008, 2016 Kenneth M. \"Elf\" Sternberg <elf.sternberg@gmail.com>"
|
"Copyright (c) 2008, 2016 Kenneth M. \"Elf\" Sternberg <elf.sternberg@gmail.com>"
|
||||||
"0.0.4")]
|
"0.0.4")]]
|
||||||
[options opts.options]
|
(if (= git-base None)
|
||||||
|
(sys.exit (_ "Not currently in a git repository."))
|
||||||
|
(try
|
||||||
|
(let [[options (.get_options opts)]
|
||||||
[config (get-config options git-base)]]
|
[config (get-config options git-base)]]
|
||||||
(cond [(.has_key options "help") (opts.print-help)]
|
(cond [(.has_key options "help") (opts.print-help)]
|
||||||
[(.has_key options "version") (opts.print-version)]
|
[(.has_key options "version") (opts.print-version)]
|
||||||
[(.has_key options "linters") (print-linters config)]
|
[(.has_key options "linters") (print-linters config)]
|
||||||
[true (git-lint-main options)]))
|
[true (run-gitlint options config opts.filenames)]))
|
||||||
(catch [err getopt.GetoptError]
|
(catch [err getopt.GetoptError]
|
||||||
(print (str err))
|
(do
|
||||||
(print-help)))))
|
(opts.print-help)))))))
|
||||||
|
|
|
@ -55,12 +55,14 @@
|
||||||
(setv self.optlist optlist)
|
(setv self.optlist optlist)
|
||||||
(setv self.options newoptions)
|
(setv self.options newoptions)
|
||||||
(setv self.excluded excluded)
|
(setv self.excluded excluded)
|
||||||
(setv self.filesames arg)
|
(setv self.filenames arg)
|
||||||
(setv self.name (if name name (get-script-name)))
|
(setv self.name (if name name (get-script-name)))
|
||||||
(setv self.version version)
|
(setv self.version version)
|
||||||
(setv self.copyright copyright))
|
(setv self.copyright copyright))
|
||||||
None)]
|
None)]
|
||||||
|
|
||||||
|
[get-options (fn [self] self.options)]
|
||||||
|
[get-keys (fn [self] (set (.keys self.options)))]
|
||||||
[print-help (fn [self]
|
[print-help (fn [self]
|
||||||
(print (.format (_ "Usage: {} [options] [filenames]") self.name))
|
(print (.format (_ "Usage: {} [options] [filenames]") self.name))
|
||||||
(for [item self.optlist] (print (.format " -{:<1} --{:<12} {}" (get item 0) (get item 1) (get item 3))))
|
(for [item self.optlist] (print (.format " -{:<1} --{:<12} {}" (get item 0) (get item 1) (get item 3))))
|
||||||
|
|
|
@ -13,14 +13,16 @@
|
||||||
(def optlist [["o" "only" true (_ "A comma-separated list of only those linters to run") ["exclude"]]
|
(def optlist [["o" "only" true (_ "A comma-separated list of only those linters to run") ["exclude"]]
|
||||||
["x" "exclude" true (_ "A comma-separated list of linters to skip") []]
|
["x" "exclude" true (_ "A comma-separated list of linters to skip") []]
|
||||||
["l" "linters" false (_ "Show the list of configured linters")]
|
["l" "linters" false (_ "Show the list of configured linters")]
|
||||||
["b" "base" false (_ "Check all changed files in the repository, not just those in the current directory.") []]
|
["b" "base" false (_ "Scan from the base directory rather than the current working") []]
|
||||||
["a" "all" false (_ "Scan all files in the repository, not just those that have changed.")]
|
["a" "all" false (_ "Scan all files in the repository, not just those that have changed")]
|
||||||
["e" "every" false (_ "Short for -b -a: scan everything")]
|
["e" "every" false (_ "Short for -b -a: scan everything")]
|
||||||
["w" "workspace" false (_ "Scan the workspace") ["staging"]]
|
["w" "workspace" false (_ "Scan the workspace") ["staging"]]
|
||||||
["s" "staging" false (_ "Scan the staging area (useful for pre-commit).") ["base" "all" "every"]]
|
["s" "staging" false (_ "Scan the staging area (useful for pre-commit).") ["base" "all" "every" "workspace"]]
|
||||||
["g" "changes" false (_ "Report lint failures only for diff'd sections") ["complete"]]
|
["g" "changes" false (_ "Report lint failures only for diff'd sections") ["complete"]]
|
||||||
["p" "complete" false (_ "Report lint failures for all files") []]
|
["p" "complete" false (_ "Report lint failures over whole files") []]
|
||||||
["c" "config" true (_ "Path to config file") []]
|
["c" "config" true (_ "Path to config file") []]
|
||||||
|
["d" "dryrun" false (_ "Report what git-lint would do, but don't actually do anything.") []]
|
||||||
|
["q" "quiet" false (_ "Produce a short report of files that failed to pass.") []]
|
||||||
["h" "help" false (_ "This help message") []]
|
["h" "help" false (_ "This help message") []]
|
||||||
["v" "version" false (_"Version information") []]])
|
["v" "version" false (_"Version information") []]])
|
||||||
|
|
||||||
|
@ -162,19 +164,26 @@
|
||||||
(print (make-match-filter config))
|
(print (make-match-filter config))
|
||||||
(print (get-porcelain-status))))
|
(print (get-porcelain-status))))
|
||||||
|
|
||||||
|
|
||||||
(defmain [&rest args]
|
(defmain [&rest args]
|
||||||
(if (= git-base None)
|
(for [option optlist]
|
||||||
(sys.exit (_ "Not currently in a git repository."))
|
(print (.format "``-{}`` ``--{}``\n {}" (get option 0) (get option 1) (get option 3)))))
|
||||||
(try
|
|
||||||
(let [[opts (hyopt optlist args "git lint"
|
|
||||||
"Copyright (c) 2008, 2016 Kenneth M. \"Elf\" Sternberg <elf.sternberg@gmail.com>"
|
;(defmain [&rest args]
|
||||||
"0.0.4")]
|
; (if (= git-base None)
|
||||||
[options opts.options]
|
; (sys.exit (_ "Not currently in a git repository."))
|
||||||
[config (get-config options git-base)]]
|
; (try
|
||||||
(cond [(.has_key options "help") (opts.print-help)]
|
; (let [[opts (hyopt optlist args "git lint"
|
||||||
[(.has_key options "version") (opts.print-version)]
|
; "Copyright (c) 2008, 2016 Kenneth M. \"Elf\" Sternberg <elf.sternberg@gmail.com>"
|
||||||
[(.has_key options "linters") (print-linters config)]
|
; "0.0.4")]
|
||||||
[true (git-lint-main options)]))
|
; [options opts.options]
|
||||||
(catch [err getopt.GetoptError]
|
; [config (get-config options git-base)]]
|
||||||
(print (str err))
|
; (cond [(.has_key options "help") (opts.print-help)]
|
||||||
(print-help)))))
|
; [(.has_key options "version") (opts.print-version)]
|
||||||
|
; [(.has_key options "linters") (print-linters config)]
|
||||||
|
; [true (git-lint-main options)]))
|
||||||
|
; (catch [err getopt.GetoptError]
|
||||||
|
; (print (str err))
|
||||||
|
; (print-help)))))
|
||||||
|
;
|
||||||
|
|
|
@ -0,0 +1,385 @@
|
||||||
|
from hy.core.language import filter, is_integer, map, reduce
|
||||||
|
import ConfigParser
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import operator
|
||||||
|
import re
|
||||||
|
import gettext
|
||||||
|
import sys
|
||||||
|
import getopt
|
||||||
|
sys.path.append(u'Users/ksternberg/build/git-lint/git_lint_src')
|
||||||
|
from git_lint_options import hyopt
|
||||||
|
from git_lint_config import get_config
|
||||||
|
_ = gettext.gettext
|
||||||
|
VERSION = u'0.0.2'
|
||||||
|
|
||||||
|
def tap(a):
|
||||||
|
print(u'TAP:', a)
|
||||||
|
return a
|
||||||
|
optlist = [[u'o', u'only', True, _(u'A comma-separated list of only those linters to run'), [u'exclude']], [u'x', u'exclude', True, _(u'A comma-separated list of linters to skip'), []], [u'l', u'linters', False, _(u'Show the list of configured linters')], [u'b', u'base', False, _(u'Check all changed files in the repository, not just those in the current directory.'), []], [u'a', u'all', False, _(u'Scan all files in the repository, not just those that have changed.')], [u'e', u'every', False, _(u'Short for -b -a: scan everything')], [u'w', u'workspace', False, _(u'Scan the workspace'), [u'staging']], [u's', u'staging', False, _(u'Scan the staging area (useful for pre-commit).'), []], [u'g', u'changes', False, _(u"Report lint failures only for diff'd sections"), [u'complete']], [u'p', u'complete', False, _(u'Report lint failures for all files'), []], [u'c', u'config', True, _(u'Path to config file'), []], [u'h', u'help', False, _(u'This help message'), []], [u'v', u'version', False, _(u'Version information'), []]]
|
||||||
|
|
||||||
|
def get_git_response_raw(cmd):
|
||||||
|
|
||||||
|
def _hy_anon_fn_2():
|
||||||
|
fullcmd = ([u'git'] + cmd)
|
||||||
|
process = subprocess.Popen(fullcmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
(out, err) = process.communicate()
|
||||||
|
(out, err)
|
||||||
|
return (out, err, process.returncode)
|
||||||
|
return _hy_anon_fn_2()
|
||||||
|
|
||||||
|
def get_git_response(cmd):
|
||||||
|
|
||||||
|
def _hy_anon_fn_4():
|
||||||
|
(out, error, returncode) = get_git_response_raw(cmd)
|
||||||
|
(out, error, returncode)
|
||||||
|
return out
|
||||||
|
return _hy_anon_fn_4()
|
||||||
|
|
||||||
|
def split_git_response(cmd):
|
||||||
|
|
||||||
|
def _hy_anon_fn_6():
|
||||||
|
(out, error, returncode) = get_git_response_raw(cmd)
|
||||||
|
(out, error, returncode)
|
||||||
|
return out.splitlines()
|
||||||
|
return _hy_anon_fn_6()
|
||||||
|
|
||||||
|
def split_git_response(cmd):
|
||||||
|
|
||||||
|
def _hy_anon_fn_8():
|
||||||
|
(out, error, returncode) = get_git_response_raw(cmd)
|
||||||
|
(out, error, returncode)
|
||||||
|
return out.splitlines()
|
||||||
|
return _hy_anon_fn_8()
|
||||||
|
|
||||||
|
def run_git_command(cmd):
|
||||||
|
|
||||||
|
def _hy_anon_fn_10():
|
||||||
|
fullcmd = ([u'git'] + cmd)
|
||||||
|
return subprocess.call(fullcmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
return _hy_anon_fn_10()
|
||||||
|
|
||||||
|
def get_shell_response(fullcmd):
|
||||||
|
|
||||||
|
def _hy_anon_fn_12():
|
||||||
|
process = subprocess.Popen(fullcmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
|
||||||
|
(out, err) = process.communicate()
|
||||||
|
(out, err)
|
||||||
|
return (out, err, process.returncode)
|
||||||
|
return _hy_anon_fn_12()
|
||||||
|
|
||||||
|
def _hy_anon_fn_14():
|
||||||
|
(out, error, returncode) = get_git_response_raw([u'rev-parse', u'--show-toplevel'])
|
||||||
|
(out, error, returncode)
|
||||||
|
return (None if (not (returncode == 0L)) else out.rstrip())
|
||||||
|
git_base = _hy_anon_fn_14()
|
||||||
|
|
||||||
|
def get_all_from_cwd():
|
||||||
|
return split_git_response([u'ls-tree', u'--name-only', u'-r', u'HEAD'])
|
||||||
|
|
||||||
|
def get_all_from_base():
|
||||||
|
return split_git_response([u'ls-tree', u'--name-only', u'-r', u'--full-tree', u'HEAD'])
|
||||||
|
MERGE_CONFLICT_PAIRS = set([u'DD', u'DU', u'AU', u'AA', u'UD', u'UA', u'UU'])
|
||||||
|
|
||||||
|
def get_changed_from_source(trackings):
|
||||||
|
|
||||||
|
def _hy_anon_fn_18():
|
||||||
|
|
||||||
|
def _hy_anon_fn_17(t):
|
||||||
|
return t([0:2], in, MERGE_CONFLICT_PAIRS)
|
||||||
|
conflicts = filter(_hy_anon_fn_17, trackings)
|
||||||
|
return (sys.exit(_(u'Current repository contains merge conflicts. Linters will not be run.')) if len(conflicts) else trackings)
|
||||||
|
return _hy_anon_fn_18()
|
||||||
|
|
||||||
|
def get_porcelain_status(cmd):
|
||||||
|
|
||||||
|
def _hy_anon_fn_22():
|
||||||
|
stream = get_git_response(cmd).split(u'\x00')
|
||||||
|
|
||||||
|
def parse_stream(acc, stream):
|
||||||
|
if (0L == len(stream)):
|
||||||
|
_hy_anon_var_1 = acc
|
||||||
|
else:
|
||||||
|
|
||||||
|
def _hy_anon_fn_20():
|
||||||
|
temp = stream.pop(0L)
|
||||||
|
index = temp.pop(0L)
|
||||||
|
workspace = temp.pop(0L)
|
||||||
|
filename = temp[1L:]
|
||||||
|
(stream.pop(0L) if (index == u'R') else None)
|
||||||
|
return parse_stream(acc.append((index, workspace, filename)), stream)
|
||||||
|
_hy_anon_var_1 = _hy_anon_fn_20()
|
||||||
|
return _hy_anon_var_1
|
||||||
|
return parse_stream([], stream)
|
||||||
|
return _hy_anon_fn_22()
|
||||||
|
|
||||||
|
def modified_in_workspace(s):
|
||||||
|
return s([0L], in, [u'M', u'A', u'?'])
|
||||||
|
|
||||||
|
def modified_in_staging(s):
|
||||||
|
return s([1L], in, [u'M', u'A', u'?'])
|
||||||
|
|
||||||
|
def get_name(s):
|
||||||
|
return s([2L])
|
||||||
|
|
||||||
|
def get_changed_from_base():
|
||||||
|
return get_changed_from_source(split_git_response([u'status', u'--porcelain', u'--untracked-files=all', git_base]))
|
||||||
|
|
||||||
|
def get_staged_from_cwd():
|
||||||
|
return []
|
||||||
|
|
||||||
|
def gen_staged_from_base():
|
||||||
|
return []
|
||||||
|
|
||||||
|
def make_match_filter_matcher(extensions):
|
||||||
|
|
||||||
|
def _hy_anon_fn_30(s):
|
||||||
|
return re.compile(s, re.I)
|
||||||
|
|
||||||
|
def _hy_anon_fn_31(s):
|
||||||
|
return ((u'\\.(' + s) + u')$')
|
||||||
|
|
||||||
|
def _hy_anon_fn_32(s):
|
||||||
|
return re.sub(u'^\\.', u'', s)
|
||||||
|
|
||||||
|
def _hy_anon_fn_33(s):
|
||||||
|
return (not (0L == len(s)))
|
||||||
|
|
||||||
|
def _hy_anon_fn_34(s):
|
||||||
|
return s.strip()
|
||||||
|
|
||||||
|
def _hy_anon_fn_35(s):
|
||||||
|
return s.split(u',')
|
||||||
|
return _hy_anon_fn_30(_hy_anon_fn_31(u'|'.join(map(_hy_anon_fn_32, filter(_hy_anon_fn_33, set(map(_hy_anon_fn_34, reduce(operator.add, map(_hy_anon_fn_35, extensions)))))))))
|
||||||
|
|
||||||
|
def make_match_filter(config):
|
||||||
|
|
||||||
|
def _hy_anon_fn_39():
|
||||||
|
|
||||||
|
def _hy_anon_fn_37(v):
|
||||||
|
return v.get(u'match', u'')
|
||||||
|
matcher = make_match_filter_matcher(map(_hy_anon_fn_37, config.itervalues()))
|
||||||
|
|
||||||
|
def _hy_anon_fn_38(path):
|
||||||
|
return matcher.search(path)
|
||||||
|
return _hy_anon_fn_38
|
||||||
|
return _hy_anon_fn_39()
|
||||||
|
|
||||||
|
def executable_exists(script, label):
|
||||||
|
if (not len(script)):
|
||||||
|
_hy_anon_var_4 = sys.exit(_(u'Syntax error in command configuration for {} ').format(label))
|
||||||
|
else:
|
||||||
|
|
||||||
|
def _hy_anon_fn_44():
|
||||||
|
scriptname = script.split(u' ')[0L]
|
||||||
|
paths = os.environ.get(u'PATH').split(u':')
|
||||||
|
|
||||||
|
def isexecutable(p):
|
||||||
|
return (os.path.exists(p) and os.access(p, os.X_OK))
|
||||||
|
if (not len(scriptname)):
|
||||||
|
_hy_anon_var_3 = sys.exit(_(u'Syntax error in command configuration for {} ').format(label))
|
||||||
|
else:
|
||||||
|
if (scriptname[0L] == u'/'):
|
||||||
|
_hy_anon_var_2 = (scriptname if isexecutable(scriptname) else None)
|
||||||
|
else:
|
||||||
|
|
||||||
|
def _hy_anon_fn_43():
|
||||||
|
|
||||||
|
def _hy_anon_fn_42(path):
|
||||||
|
return isexecutable(os.path.join(path, scriptname))
|
||||||
|
possibles = list(filter(_hy_anon_fn_42, paths))
|
||||||
|
return (possibles[0L] if len(possibles) else None)
|
||||||
|
_hy_anon_var_2 = _hy_anon_fn_43()
|
||||||
|
_hy_anon_var_3 = _hy_anon_var_2
|
||||||
|
return _hy_anon_var_3
|
||||||
|
_hy_anon_var_4 = _hy_anon_fn_44()
|
||||||
|
return _hy_anon_var_4
|
||||||
|
|
||||||
|
def print_linters(config):
|
||||||
|
print(_(u'Currently supported linters:'))
|
||||||
|
for (linter, items) in config.iteritems():
|
||||||
|
(print(u'{:<14} {}'.format(linter, _(u'(WARNING: executable not found)'))) if (not executable_exists(items.get(u'command', u''), linter)) else print(u'{:<14} {}'.format(linter, items.get(u'comment', u''))))
|
||||||
|
|
||||||
|
def get_porcelain_status():
|
||||||
|
|
||||||
|
def _hy_anon_fn_50():
|
||||||
|
cmd = [u'status', u'-z', u'--porcelain', u'--untracked-files=all', u'--ignore-submodules=all']
|
||||||
|
|
||||||
|
def nonnull(s):
|
||||||
|
return (len(s) > 0L)
|
||||||
|
stream = tap(list(filter(nonnull, get_git_response(cmd).split(u'\x00'))))
|
||||||
|
|
||||||
|
def parse_stream(acc, stream):
|
||||||
|
if (0L == len(stream)):
|
||||||
|
_hy_anon_var_5 = acc
|
||||||
|
else:
|
||||||
|
|
||||||
|
def _hy_anon_fn_48():
|
||||||
|
temp = stream.pop(0L)
|
||||||
|
index = temp[0L]
|
||||||
|
workspace = temp[1L]
|
||||||
|
filename = tap(temp[3L:])
|
||||||
|
(stream.pop(0L) if (index == u'R') else None)
|
||||||
|
return parse_stream((acc + [(index, workspace, filename)]), stream)
|
||||||
|
_hy_anon_var_5 = _hy_anon_fn_48()
|
||||||
|
return _hy_anon_var_5
|
||||||
|
return parse_stream([], stream)
|
||||||
|
return _hy_anon_fn_50()
|
||||||
|
|
||||||
|
def staging_wrapper(files, run_linters):
|
||||||
|
|
||||||
|
def _hy_anon_fn_55():
|
||||||
|
|
||||||
|
def time_gather(f):
|
||||||
|
|
||||||
|
def _hy_anon_fn_52():
|
||||||
|
stats = os.stat(f)
|
||||||
|
return (f, (stats.atime, stats.mtime))
|
||||||
|
return _hy_anon_fn_52()
|
||||||
|
times = list(map(time_gather, files))
|
||||||
|
run_git_command([u'stash', u'--keep-index'])
|
||||||
|
|
||||||
|
def _hy_anon_fn_54():
|
||||||
|
results = run_linters(files)
|
||||||
|
run_git_command([u'reset', u'--hard'])
|
||||||
|
run_git_command([u'stash', u'pop', u'--quiet', u'--index'])
|
||||||
|
for (filename, timepair) in times:
|
||||||
|
os.utime(filename, timepair)
|
||||||
|
return results
|
||||||
|
return _hy_anon_fn_54()
|
||||||
|
return _hy_anon_fn_55()
|
||||||
|
|
||||||
|
def workspace_wrapper(files, run_linters):
|
||||||
|
return run_linters(files)
|
||||||
|
|
||||||
|
def remove_submodules(files):
|
||||||
|
|
||||||
|
def _hy_anon_fn_62():
|
||||||
|
|
||||||
|
def split_out_paths(s):
|
||||||
|
return s.split(u' ')[2L]
|
||||||
|
fixer_re = re.compile(u'^(\\.\\.\\/)+')
|
||||||
|
|
||||||
|
def fixer_to_base(s):
|
||||||
|
return fixer_re.sub(u'', s)
|
||||||
|
submodule_entries = split_git_response([u'submodule', u'status'])
|
||||||
|
|
||||||
|
def _hy_anon_fn_60(s):
|
||||||
|
return fixer_to_base(split_out_paths(s))
|
||||||
|
submodule_names = map(_hy_anon_fn_60, submodule_entries)
|
||||||
|
|
||||||
|
def _hy_anon_fn_61(s):
|
||||||
|
return (not (s in submodule_names))
|
||||||
|
return filter(_hy_anon_fn_61, submodule_names)
|
||||||
|
return _hy_anon_fn_62()
|
||||||
|
|
||||||
|
def base_file_filter(files):
|
||||||
|
|
||||||
|
def _hy_anon_fn_64(f):
|
||||||
|
return os.path.join(git_base, f)
|
||||||
|
return map(_hy_anon_fn_64, files)
|
||||||
|
|
||||||
|
def cwd_file_filter(files):
|
||||||
|
|
||||||
|
def _hy_anon_fn_67():
|
||||||
|
gitcwd = os.path.join(os.path.relpath(os.getcwd(), git_base), u'')
|
||||||
|
|
||||||
|
def _hy_anon_fn_66(f):
|
||||||
|
return f.startswith(gitcwd)
|
||||||
|
return base_file_filter(filter(_hy_anon_fn_66, files))
|
||||||
|
return _hy_anon_fn_67()
|
||||||
|
|
||||||
|
def base_file_cleaner(files):
|
||||||
|
|
||||||
|
def _hy_anon_fn_69(f):
|
||||||
|
return f.replace(git_base, 1L)
|
||||||
|
return map(_hy_anon_fn_69, files)
|
||||||
|
|
||||||
|
def staging_list():
|
||||||
|
|
||||||
|
def _hy_anon_fn_71(_hy_anon_var_6):
|
||||||
|
(index, workspace, filename) = _hy_anon_var_6
|
||||||
|
(index, workspace, filename)
|
||||||
|
return filename
|
||||||
|
|
||||||
|
def _hy_anon_fn_72(_hy_anon_var_7):
|
||||||
|
(index, workspace, filename) = _hy_anon_var_7
|
||||||
|
(index, workspace, filename)
|
||||||
|
return (index in [u'A', u'M'])
|
||||||
|
return map(_hy_anon_fn_71, filter(_hy_anon_fn_72, get_porcelain_status))
|
||||||
|
|
||||||
|
def working_list():
|
||||||
|
|
||||||
|
def _hy_anon_fn_74(_hy_anon_var_8):
|
||||||
|
(index, workspace, filename) = _hy_anon_var_8
|
||||||
|
(index, workspace, filename)
|
||||||
|
return filename
|
||||||
|
|
||||||
|
def _hy_anon_fn_75(_hy_anon_var_9):
|
||||||
|
(index, workspace, filename) = _hy_anon_var_9
|
||||||
|
(index, workspace, filename)
|
||||||
|
return (working in [u'A', u'M', u'?'])
|
||||||
|
return map(_hy_anon_fn_74, filter(_hy_anon_fn_75, get_porcelain_status))
|
||||||
|
|
||||||
|
def all_list():
|
||||||
|
|
||||||
|
def _hy_anon_fn_78():
|
||||||
|
cmd = [u'ls-tree', u'--name-only', u'--full-tree', u'-r', git_head]
|
||||||
|
|
||||||
|
def _hy_anon_fn_77(s):
|
||||||
|
return (len(s) > 0L)
|
||||||
|
return filter(_hy_anon_fn_77, get_git_response(cmd).split(u'\x00'))
|
||||||
|
return _hy_anon_fn_78()
|
||||||
|
|
||||||
|
def pick_filelist_strategy(options):
|
||||||
|
|
||||||
|
def _hy_anon_fn_81():
|
||||||
|
keys = options.keys()
|
||||||
|
working_directory_trans = (base_file_filter if len((set(keys) & set([u'b', u'e']))) else cwd_file_filter)
|
||||||
|
file_list_generator = (staging_list if (u's' in keys) else (all_list if (u'a' in keys) else (working_list if True else None)))
|
||||||
|
|
||||||
|
def _hy_anon_fn_80():
|
||||||
|
return working_directory_trans(remove_submodules(file_list_generator()))
|
||||||
|
return _hy_anon_fn_80
|
||||||
|
return _hy_anon_fn_81()
|
||||||
|
|
||||||
|
def pick_runner(options):
|
||||||
|
|
||||||
|
def _hy_anon_fn_83():
|
||||||
|
keys = options.keys()
|
||||||
|
return (staging_wrapper if (u's' in keys) else workspace_wrapper)
|
||||||
|
return _hy_anon_fn_83()
|
||||||
|
|
||||||
|
def run_gitlint(options, config, extras):
|
||||||
|
|
||||||
|
def _hy_anon_fn_85():
|
||||||
|
file_lister = pick_filelist_strategy(options)
|
||||||
|
runner = pick_runner(options)
|
||||||
|
return print(file_lister())
|
||||||
|
return _hy_anon_fn_85()
|
||||||
|
|
||||||
|
def main(*args):
|
||||||
|
|
||||||
|
def _hy_anon_fn_88():
|
||||||
|
opts = hyopt(optlist, args, u'git lint', u'Copyright (c) 2008, 2016 Kenneth M. "Elf" Sternberg <elf.sternberg@gmail.com>', u'0.0.4')
|
||||||
|
if (git_base == None):
|
||||||
|
_hy_anon_var_11 = sys.exit(_(u'Not currently in a git repository.'))
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
|
||||||
|
def _hy_anon_fn_87():
|
||||||
|
options = opts.get_options()
|
||||||
|
config = get_config(options, git_base)
|
||||||
|
return (opts.print_help() if options.has_key(u'help') else (opts.print_version() if options.has_key(u'version') else (print_linters(config) if options.has_key(u'linters') else (run_gitlint(options, config, opts.filenames) if True else None))))
|
||||||
|
_hy_anon_var_10 = _hy_anon_fn_87()
|
||||||
|
except getopt.GetoptError as err:
|
||||||
|
_hy_anon_var_10 = opts.print_help()
|
||||||
|
_hy_anon_var_11 = _hy_anon_var_10
|
||||||
|
return _hy_anon_var_11
|
||||||
|
return _hy_anon_fn_88()
|
||||||
|
if (__name__ == u'__main__'):
|
||||||
|
import sys
|
||||||
|
:G_1235 = main(*sys.argv)
|
||||||
|
_hy_anon_var_12 = (sys.exit(:G_1235) if is_integer(:G_1235) else None)
|
||||||
|
else:
|
||||||
|
_hy_anon_var_12 = None
|
Loading…
Reference in New Issue