diff options
-rw-r--r-- | .config.sample | 6 | ||||
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | README.md | 29 | ||||
l--------- | ject | 1 | ||||
-rwxr-xr-x | scripts/base.py | 108 | ||||
-rwxr-xr-x | scripts/find.py | 124 | ||||
-rwxr-xr-x | scripts/ject.py | 16 | ||||
-rwxr-xr-x | scripts/view.py | 122 |
8 files changed, 408 insertions, 0 deletions
diff --git a/.config.sample b/.config.sample new file mode 100644 index 0000000..1350199 --- /dev/null +++ b/.config.sample @@ -0,0 +1,6 @@ +viewer:less -RXE + +# color = escape sequence +key:33 +status:01;46 +team:32 @@ -1 +1,3 @@ .config +scripts/__pycache__/ + @@ -15,3 +15,32 @@ developed to aid the creation and manipulation of the data sources. use cases in the future. See: - https://pykwalify.readthedocs.io/en/unstable/extensions.html#how-custom-validation-works + +# ject + +## How to use ? +You can check project via ject command. +You need to have **.config** file. You can copy sample .config, and edit it + +`cp .config.sample .config` + +## options + + * key : show matched key task + - ject 7ddd3743-fa13-4966-bcf0-10609b873ab5 + - ject 7ddd3743-fa13-4966-bcf0-10609b873ab5 e704e989-ccaa-48a5-8f58-28c5b93467ff + * -s : show matched status task + * -ns : show unmatched status task + - ject -s Active ... # single match + - ject -s Active,New ... # multi match + - ject -ns Done # not match + * -a : show matched assignee task + * -as : show unmatched assignee task + - ject -a Wolfram ... + - ject -na Morimoto,Shimoda ... + * -t : show matched team task + * -at : show unmatched team task + - ject -t IO,MM ... + - ject -nt Core ... + * -f : show with file name + * --oneline : show one line @@ -0,0 +1 @@ +scripts/ject.py
\ No newline at end of file diff --git a/scripts/base.py b/scripts/base.py new file mode 100755 index 0000000..1a6396e --- /dev/null +++ b/scripts/base.py @@ -0,0 +1,108 @@ +#! /usr/bin/env python3 +#=============================== +# +# base +# +# 2019/02/07 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> +#=============================== +import os +import re +import subprocess + +#==================================== +# +# base +# +# it supports do/run/run1 for using external command +# +#==================================== +class base: + __top = os.path.abspath(__file__ + "/../../"); + __key = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" + + #-------------------- + # chomp + #-------------------- + def chomp(self, text): + return re.sub(r"\n$", r"", text); + + #-------------------- + # top() + #-------------------- + def top(self): + return base.__top; + + #-------------------- + # is_key() + #-------------------- + def is_key(self, key): + return re.match(base.__key, key); + + #-------------------- + # color + #-------------------- + def color(self, color, text): + return "\033[{}m{}\033[0m".format(self.config(color), text) + + #-------------------- + # do() + # + # do command + #-------------------- + def do(self, command): + return subprocess.run(command, shell=True).returncode; + + #-------------------- + # tolist() + #-------------------- + def tolist(self, string): + if (len(string) > 0): + return string.split('\n'); + + return []; + + #-------------------- + # run() + # + # run command and get result as plane text + #-------------------- + def run(self, command): + + # Ughhhh + # I don't like python external command !! + # (ノ `Д´)ノ go away !! + return self.chomp(subprocess.Popen(command, shell=True, stdout=subprocess.PIPE).\ + communicate()[0].decode("utf-8")); + + #-------------------- + # run1() + # + # run command and get result as list + #-------------------- + def runl(self, command): + + # call run() and exchange result as array + # + # "xxxxxxx + # yyyyyyy + # zzzzzzz" + # -> + # ["xxxxxxx", + # "yyyyyyy", + # "zzzzzzz"] + return self.tolist(self.run(command)); + + #-------------------- + # config() + # + # read settings from config + #-------------------- + def config(self, item): + if (not os.path.exists("{}/.config".format(self.top()))): + print("\nplease copy .config.sample to .config\n" + + "and edit it for your environment\n"); + exit(); + + config = self.run("grep {} {}/.config | cut -d : -f2".\ + format(item, self.top())); + return self.chomp(config); diff --git a/scripts/find.py b/scripts/find.py new file mode 100755 index 0000000..3150475 --- /dev/null +++ b/scripts/find.py @@ -0,0 +1,124 @@ +#! /usr/bin/env python3 +#=============================== +# +# find +# +# 2019/02/07 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> +#=============================== +import sys +import os +import re + +import base + +#==================================== +# +# find +# +#==================================== +class find(base.base): + + #-------------------- + # default_arg + #-------------------- + def default_arg(self, arg): + # add "-ns Done" automatically + # if user doesn't specify "-s" or "-ns" + match = 0 + for cmd in arg: + if ((cmd == "-s") or (cmd == "-ns")): + match = 1 + + if (not match): + return ["-ns", "Done"] + + return [] + + #-------------------- + # parse_option + #-------------------- + def parse_option(self, arg, option, char, hit): + + op = "-l" # hit + if (not hit): + op = "-L" # not hit + + match = 0 + for cmd in arg: + if (cmd == option): + match = 1 + elif (match): + # Wolfram,Shimoda + # -> + # (Wolfram|Shimoda) + tgt = "({})".format(cmd.replace(",", "|")) + + self.files = self.run("echo \"{}\" | xargs egrep {} \"{}:\s+{}\"".\ + format(self.files, op, char, tgt)) + return + + #-------------------- + # parse_files + #-------------------- + def parse_files(self, arg): + + # find specified key files if exist + for key in arg: + if (not self.is_key(key)): + continue + + if (len(self.files) > 0): + self.files += "\n" + + self.files += self.run("egrep -l \"key:\s+{}\" -r {}/projects".\ + format(key, self.top())) + + # all project files if no files + if (len(self.files) == 0): + self.files = self.run("find {}/projects -type f | grep -v schema".\ + format(self.top())) + + #-------------------- + # __init__ + #-------------------- + def __init__(self, arg): + super().__init__() + + self.files = "" + + self.parse_files(arg) + + arg += self.default_arg(arg) + + # -s : matched status + # -ns : not matched status + # -a : matched assignee + # -na : not matched assignee + # -t : matched team + # -nt : not matched team + self.parse_option(arg, "-s", "status", 1) + self.parse_option(arg, "-ns", "status", 0) + self.parse_option(arg, "-a", "assignee", 1) + self.parse_option(arg, "-na", "assignee", 0) + self.parse_option(arg, "-t", "team", 1) + self.parse_option(arg, "-nt", "team", 0) + + #-------------------- + # get + #-------------------- + def get(self): + return self.tolist(self.files) + + #-------------------- + # show + #-------------------- + def show(self): + print(self.files) + +#==================================== +# +# As command +# +#==================================== +if __name__=='__main__': + find(sys.argv).show() diff --git a/scripts/ject.py b/scripts/ject.py new file mode 100755 index 0000000..b0b469f --- /dev/null +++ b/scripts/ject.py @@ -0,0 +1,16 @@ +#! /usr/bin/env python3 +#=============================== +# +# ject +# +# 2019/02/12 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> +#=============================== +import sys + +import find +import view + +param = sys.argv + +view.viewer(param + find.find(param).get()).show() + diff --git a/scripts/view.py b/scripts/view.py new file mode 100755 index 0000000..b73095c --- /dev/null +++ b/scripts/view.py @@ -0,0 +1,122 @@ +#! /usr/bin/env python3 +#=============================== +# +# viewer +# +# 2019/02/07 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> +#=============================== +import yaml +import sys +import os +import re + +import base + +#==================================== +# +# viewer +# +#==================================== +class viewer(base.base): + + #-------------------- + # parse + # + # -f : with file + # --oneline: one line + #-------------------- + def parse(self, arg): + for arg in arg: + if (arg == "-f"): + self.with_file = 1 + elif (arg == "--oneline"): + self.one_line = 1 + elif (os.path.exists(arg) and + re.match("{}/projects".format(self.top()), + os.path.abspath(arg))): + self.files += [arg] + + #-------------------- + # __init__ + #-------------------- + def __init__(self, arg): + + self.text = "" + self.files = [] + self.with_file = 0 + self.one_line = 0 + + self.parse(arg) + + #-------------------- + # make_one + # for --oneline + #-------------------- + def make_one(self, file, data): + + if (len(self.text) > 0): + self.text += "\n" + + # show "key" + self.text += "{}: {}".format( + self.color("key", data["key"]), + data["title"]) + + #-------------------- + # make_full + # for normal + #-------------------- + def make_full(self, file, data): + + if (len(self.text) > 0): + self.text += "\n" + + # show "key" + self.text += "{}, {}, {}\n".format( + self.color("key", data["key"]), + self.color("status", data["status"]), + self.color("team", data["team"])); + + # show title + self.text += "Title: {}\n".format(data["title"]) + + # show assignee + self.text += "Assignee: {}\n".format(data["assignee"]) + + if (self.with_file): + self.text += "File: {}\n".format( + os.path.abspath(file).replace("{}/".format(self.top()), "")) + + # show comments + comments = data["comments"] + if (comments): + for comment in comments: + self.text += "\n{}".format(comment) + + #-------------------- + # show + #-------------------- + def show(self): + for f in self.files: + F = open(f, "r+") + data = yaml.load(F) + F.close() + + if (self.one_line): + self.make_one(f, data) + else: + self.make_full(f, data) + + # escape " -> \" + # otherwise " will be disappeared + self.text = self.text.replace("\"", "\\\""); + self.do("echo \"{}\" | {}".format( + self.text, self.config("viewer"))) + +#==================================== +# +# As command +# +#==================================== +if __name__=='__main__': + viewer(sys.argv).show() |