diff --git a/IPA_Font_License_Agreement_v1.0.txt b/IPA_Font_License_Agreement_v1.0.txt deleted file mode 100644 index fe8db24..0000000 --- a/IPA_Font_License_Agreement_v1.0.txt +++ /dev/null @@ -1,117 +0,0 @@ --------------------------------------------------- -IPA Font License Agreement v1.0 --------------------------------------------------- - -IPAフォントライセンスv1.0 - -許諾者は、この使用許諾(以下「本契約」といいます。)に定める条件の下で、許諾プログラム(1条に定義するところによります。)を提供します。受領者(1条に定義するところによります。)が、許諾プログラムを使用し、複製し、または頒布する行為、その他、本契約に定める権利の利用を行った場合、受領者は本契約に同意したものと見なします。 - - -第1条 用語の定義 - -本契約において、次の各号に掲げる用語は、当該各号に定めるところによります。 - -1.「デジタル・フォント・プログラム」とは、フォントを含み、レンダリングしまたは表示するために用いられるコンピュータ・プログラムをいいます。 -2.「許諾プログラム」とは、許諾者が本契約の下で許諾するデジタル・フォント・プログラムをいいます。 -3.「派生プログラム」とは、許諾プログラムの一部または全部を、改変し、加除修正等し、入れ替え、その他翻案したデジタル・フォント・プログラムをいい、許諾プログラムの一部もしくは全部から文字情報を取り出し、またはデジタル・ドキュメント・ファイルからエンベッドされたフォントを取り出し、取り出された文字情報をそのまま、または改変をなして新たなデジタル・フォント・プログラムとして製作されたものを含みます。 -4.「デジタル・コンテンツ」とは、デジタル・データ形式によってエンド・ユーザに提供される制作物のことをいい、動画・静止画等の映像コンテンツおよびテレビ番組等の放送コンテンツ、ならびに文字テキスト、画像、図形等を含んで構成された制作物を含みます。 -5.「デジタル・ドキュメント・ファイル」とは、PDFファイルその他、各種ソフトウェア・プログラムによって製作されたデジタル・コンテンツであって、その中にフォントを表示するために許諾プログラムの全部または一部が埋め込まれた(エンベッドされた)ものをいいます。フォントが「エンベッドされた」とは、当該フォントが埋め込まれた特定の「デジタル・ドキュメント・ファイル」においてのみ表示されるために使用されている状態を指し、その特定の「デジタル・ドキュメント・ファイル」以外でフォントを表示するために使用できるデジタル・フォント・プログラムに含まれている場合と区別されます。 -6.「コンピュータ」とは、本契約においては、サーバを含みます。 -7.「複製その他の利用」とは、複製、譲渡、頒布、貸与、公衆送信、上映、展示、翻案その他の利用をいいます。 -8.「受領者」とは、許諾プログラムを本契約の下で受領した人をいい、受領者から許諾プログラムを受領した人を含みます。 - -第2条 使用許諾の付与 - -許諾者は受領者に対し、本契約の条項に従い、すべての国で、許諾プログラムを使用することを許諾します。ただし、許諾プログラムに存在する一切の権利はすべて許諾者が保有しています。本契約は、本契約で明示的に定められている場合を除き、いかなる意味においても、許諾者が保有する許諾プログラムに関する一切の権利および、いかなる商標、商号、もしくはサービス・マークに関する権利をも受領者に移転するものではありません。 - -1.受領者は本契約に定める条件に従い、許諾プログラムを任意の数のコンピュータにインストールし、当該コンピュータで使用することができます。 -2.受領者はコンピュータにインストールされた許諾プログラムをそのまま、または改変を行ったうえで、印刷物およびデジタル・コンテンツにおいて、文字テキスト表現等として使用することができます。 -3.受領者は前項の定めに従い作成した印刷物およびデジタル・コンテンツにつき、その商用・非商用の別、および放送、通信、各種記録メディアなどの媒体の形式を問わず、複製その他の利用をすることができます。 -4.受領者がデジタル・ドキュメント・ファイルからエンベッドされたフォントを取り出して派生プログラムを作成した場合には、かかる派生プログラムは本契約に定める条件に従う必要があります。 -5.許諾プログラムのエンベッドされたフォントがデジタル・ドキュメント・ファイル内のデジタル・コンテンツをレンダリングするためにのみ使用される場合において、受領者が当該デジタル・ドキュメント・ファイルを複製その他の利用をする場合には、受領者はかかる行為に関しては本契約の下ではいかなる義務をも負いません。 -6.受領者は、3条2項の定めに従い、商用・非商用を問わず、許諾プログラムをそのままの状態で改変することなく複製して第三者への譲渡し、公衆送信し、その他の方法で再配布することができます(以下、「再配布」といいます。)。 -7.受領者は、上記の許諾プログラムについて定められた条件と同様の条件に従って、派生プログラムを作成し、使用し、複製し、再配布することができます。ただし、受領者が派生プログラムを再配布する場合には、3条1項の定めに従うものとします。 - -第3条 制限 - -前条により付与された使用許諾は、以下の制限に服します。 - -1.派生プログラムが前条4項及び7項に基づき再配布される場合には、以下の全ての条件を満たさなければなりません。 - (1)派生プログラムを再配布する際には、下記もまた、当該派生プログラムと一緒に再配布され、オンラインで提供され、または、郵送費・媒体及び取扱手数料の合計を超えない実費と引き換えに媒体を郵送する方法により提供されなければなりません。 -  (a)派生プログラムの写し; および -  (b)派生プログラムを作成する過程でフォント開発プログラムによって作成された追加のファイルであって派生プログラムをさらに加工するにあたって利用できるファイルが存在すれば、当該ファイル - (2)派生プログラムの受領者が、派生プログラムを、このライセンスの下で最初にリリースされた許諾プログラム(以下、「オリジナル・プログラム」といいます。)に置き換えることができる方法を再配布するものとします。かかる方法は、オリジナル・ファイルからの差分ファイルの提供、または、派生プログラムをオリジナル・プログラムに置き換える方法を示す指示の提供などが考えられます。 - (3)派生プログラムを、本契約書に定められた条件の下でライセンスしなければなりません。 - (4)派生プログラムのプログラム名、フォント名またはファイル名として、許諾プログラムが用いているのと同一の名称、またはこれを含む名称を使用してはなりません。 - (5)本項の要件を満たすためにオンラインで提供し、または媒体を郵送する方法で提供されるものは、その提供を希望するいかなる者によっても提供が可能です。 -2.受領者が前条6項に基づき許諾プログラムを再配布する場合には、以下の全ての条件を満たさなければなりません。 - (1)許諾プログラムの名称を変更してはなりません。 - (2)許諾プログラムに加工その他の改変を加えてはなりません。 - (3)本契約の写しを許諾プログラムに添付しなければなりません。 -3.許諾プログラムは、現状有姿で提供されており、許諾プログラムまたは派生プログラムについて、許諾者は一切の明示または黙示の保証(権利の所在、非侵害、商品性、特定目的への適合性を含むがこれに限られません)を行いません。いかなる場合にも、その原因を問わず、契約上の責任か厳格責任か過失その他の不法行為責任かにかかわらず、また事前に通知されたか否かにかかわらず、許諾者は、許諾プログラムまたは派生プログラムのインストール、使用、複製その他の利用または本契約上の権利の行使によって生じた一切の損害(直接・間接・付随的・特別・拡大・懲罰的または結果的損害)(商品またはサービスの代替品の調達、システム障害から生じた損害、現存するデータまたはプログラムの紛失または破損、逸失利益を含むがこれに限られません)について責任を負いません。 -4.許諾プログラムまたは派生プログラムのインストール、使用、複製その他の利用に関して、許諾者は技術的な質問や問い合わせ等に対する対応その他、いかなるユーザ・サポートをも行う義務を負いません。 - -第4条 契約の終了 - -1.本契約の有効期間は、受領者が許諾プログラムを受領した時に開始し、受領者が許諾プログラムを何らかの方法で保持する限り続くものとします。 -2.前項の定めにかかわらず、受領者が本契約に定める各条項に違反したときは、本契約は、何らの催告を要することなく、自動的に終了し、当該受領者はそれ以後、許諾プログラムおよび派生プログラムを一切使用しまたは複製その他の利用をすることができないものとします。ただし、かかる契約の終了は、当該違反した受領者から許諾プログラムまたは派生プログラムの配布を受けた受領者の権利に影響を及ぼすものではありません。 - -第5条 準拠法 - -1.IPAは、本契約の変更バージョンまたは新しいバージョンを公表することができます。その場合には、受領者は、許諾プログラムまたは派生プログラムの使用、複製その他の利用または再配布にあたり、本契約または変更後の契約のいずれかを選択することができます。その他、上記に記載されていない条項に関しては日本の著作権法および関連法規に従うものとします。 -2.本契約は、日本法に基づき解釈されます。 - - ----------- - -IPA Font License Agreement v1.0 - -The Licensor provides the Licensed Program (as defined in Article 1 below) under the terms of this license agreement (“Agreement”). Any use, reproduction or distribution of the Licensed Program, or any exercise of rights under this Agreement by a Recipient (as defined in Article 1 below) constitutes the Recipient's acceptance of this Agreement. - -Article 1 (Definitions) -1.“Digital Font Program” shall mean a computer program containing, or used to render or display fonts. -2.“Licensed Program” shall mean a Digital Font Program licensed by the Licensor under this Agreement. -3.“Derived Program” shall mean a Digital Font Program created as a result of a modification, addition, deletion, replacement or any other adaptation to or of a part or all of the Licensed Program, and includes a case where a Digital Font Program newly created by retrieving font information from a part or all of the Licensed Program or Embedded Fonts from a Digital Document File with or without modification of the retrieved font information. -4.“Digital Content” shall mean products provided to end users in the form of digital data, including video content, motion and/or still pictures, TV programs or other broadcasting content and products consisting of character text, pictures, photographic images, graphic symbols and/or the like. -5.“Digital Document File” shall mean a PDF file or other Digital Content created by various software programs in which a part or all of the Licensed Program becomes embedded or contained in the file for the display of the font (“Embedded Fonts”). Embedded Fonts are used only in the display of characters in the particular Digital Document File within which they are embedded, and shall be distinguished from those in any Digital Font Program, which may be used for display of characters outside that particular Digital Document File. -6.“Computer” shall include a server in this Agreement. -7.“Reproduction and Other Exploitation” shall mean reproduction, transfer, distribution, lease, public transmission, presentation, exhibition, adaptation and any other exploitation. -8.“Recipient” shall mean anyone who receives the Licensed Program under this Agreement, including one that receives the Licensed Program from a Recipient. - -Article 2 (Grant of License) -The Licensor grants to the Recipient a license to use the Licensed Program in any and all countries in accordance with each of the provisions set forth in this Agreement. However, any and all rights underlying in the Licensed Program shall be held by the Licensor. In no sense is this Agreement intended to transfer any right relating to the Licensed Program held by the Licensor except as specifically set forth herein or any right relating to any trademark, trade name, or service mark to the Recipient. - -1.The Recipient may install the Licensed Program on any number of Computers and use the same in accordance with the provisions set forth in this Agreement. -2.The Recipient may use the Licensed Program, with or without modification in printed materials or in Digital Content as an expression of character texts or the like. -3.The Recipient may conduct Reproduction and Other Exploitation of the printed materials and Digital Content created in accordance with the preceding Paragraph, for commercial or non-commercial purposes and in any form of media including but not limited to broadcasting, communication and various recording media. -4.If any Recipient extracts Embedded Fonts from a Digital Document File to create a Derived Program, such Derived Program shall be subject to the terms of this agreement. -5.If any Recipient performs Reproduction or Other Exploitation of a Digital Document File in which Embedded Fonts of the Licensed Program are used only for rendering the Digital Content within such Digital Document File then such Recipient shall have no further obligations under this Agreement in relation to such actions. -6.The Recipient may reproduce the Licensed Program as is without modification and transfer such copies, publicly transmit or otherwise redistribute the Licensed Program to a third party for commercial or non-commercial purposes (“Redistribute”), in accordance with the provisions set forth in Article 3 Paragraph 2. -7.The Recipient may create, use, reproduce and/or Redistribute a Derived Program under the terms stated above for the Licensed Program: provided, that the Recipient shall follow the provisions set forth in Article 3 Paragraph 1 when Redistributing the Derived Program. - -Article 3 (Restriction) -The license granted in the preceding Article shall be subject to the following restrictions: - -1.If a Derived Program is Redistributed pursuant to Paragraph 4 and 7 of the preceding Article, the following conditions must be met : - (1)The following must be also Redistributed together with the Derived Program, or be made available online or by means of mailing mechanisms in exchange for a cost which does not exceed the total costs of postage, storage medium and handling fees: -  (a)a copy of the Derived Program; and -  (b)any additional file created by the font developing program in the course of creating the Derived Program that can be used for further modification of the Derived Program, if any. - (2)It is required to also Redistribute means to enable recipients of the Derived Program to replace the Derived Program with the Licensed Program first released under this License (the “Original Program”). Such means may be to provide a difference file from the Original Program, or instructions setting out a method to replace the Derived Program with the Original Program. - (3)The Recipient must license the Derived Program under the terms and conditions of this Agreement. - (4)No one may use or include the name of the Licensed Program as a program name, font name or file name of the Derived Program. - (5)Any material to be made available online or by means of mailing a medium to satisfy the requirements of this paragraph may be provided, verbatim, by any party wishing to do so. -2.If the Recipient Redistributes the Licensed Program pursuant to Paragraph 6 of the preceding Article, the Recipient shall meet all of the following conditions: - (1)The Recipient may not change the name of the Licensed Program. - (2)The Recipient may not alter or otherwise modify the Licensed Program. - (3)The Recipient must attach a copy of this Agreement to the Licensed Program. -3.THIS LICENSED PROGRAM IS PROVIDED BY THE LICENSOR “AS IS” AND ANY EXPRESSED OR IMPLIED WARRANTY AS TO THE LICENSED PROGRAM OR ANY DERIVED PROGRAM, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXTENDED, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO; PROCUREMENT OF SUBSTITUTED GOODS OR SERVICE; DAMAGES ARISING FROM SYSTEM FAILURE; LOSS OR CORRUPTION OF EXISTING DATA OR PROGRAM; LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE INSTALLATION, USE, THE REPRODUCTION OR OTHER EXPLOITATION OF THE LICENSED PROGRAM OR ANY DERIVED PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. -4.The Licensor is under no obligation to respond to any technical questions or inquiries, or provide any other user support in connection with the installation, use or the Reproduction and Other Exploitation of the Licensed Program or Derived Programs thereof. - -Article 4 (Termination of Agreement) -1.The term of this Agreement shall begin from the time of receipt of the Licensed Program by the Recipient and shall continue as long as the Recipient retains any such Licensed Program in any way. -2.Notwithstanding the provision set forth in the preceding Paragraph, in the event of the breach of any of the provisions set forth in this Agreement by the Recipient, this Agreement shall automatically terminate without any notice. In the case of such termination, the Recipient may not use or conduct Reproduction and Other Exploitation of the Licensed Program or a Derived Program: provided that such termination shall not affect any rights of any other Recipient receiving the Licensed Program or the Derived Program from such Recipient who breached this Agreement. - -Article 5 (Governing Law) -1.IPA may publish revised and/or new versions of this License. In such an event, the Recipient may select either this Agreement or any subsequent version of the Agreement in using, conducting the Reproduction and Other Exploitation of, or Redistributing the Licensed Program or a Derived Program. Other matters not specified above shall be subject to the Copyright Law of Japan and other related laws and regulations of Japan. -2.This Agreement shall be construed under the laws of Japan. - diff --git a/cmd_clone.py b/cmd_clone.py deleted file mode 100644 index 1a41fb0..0000000 --- a/cmd_clone.py +++ /dev/null @@ -1,49 +0,0 @@ -# clone - -import os - -import repo - -# フォルダを削除 -def rmtree(top): - for root, dirs, files in os.walk(top, topdown=False): - for name in files: - filename = os.path.join(root, name) - os.chmod(filename, 0o777) - os.remove(filename) - for name in dirs: - os.rmdir(os.path.join(root, name)) - os.rmdir(top) - -def run(first_flag): - root_path = "project" # レポジトリのパス - - print("解析するレポジトリのURLを入力してください") - url = input(">>> ") - - # 最初だけ確認 - if os.path.isdir(root_path): - if first_flag == 0: - rmtree(root_path) # projectフォルダが存在していれば削除 - - clone_flag = True - while clone_flag: - try: - # "://"でURLか判定 - if url.find("://"): - file_name = url[url.rfind('/') + 1:] # 一番後ろのファイル名を抽出 - - path = root_path + "/" + file_name # project/.. - - # 既にクローン済みの場合、pathの最後に(i)をつける - i = 1 - while os.path.isdir(path): - path = root_path + "/" + file_name + "({:d})".format(i) - i += 1 - - repo.clone_repo(url, path) # レポジトリをクローン - print("レポジトリをクローンしました\n") - clone_flag = False - except Exception as err: - print("レポジトリをクローン出来ませんでした\nもう一度、入力してください") - url = input(">>> ") \ No newline at end of file diff --git a/cmd_diff.py b/cmd_diff.py deleted file mode 100644 index 58c568d..0000000 --- a/cmd_diff.py +++ /dev/null @@ -1,46 +0,0 @@ -# diff - -import sys -from tqdm import tqdm - -# 変更行から文字を検索し、その行を抜き出す -def search_lines(repo, hexsha_after, hexsha_before, commit_no): - s = repo.git.diff(hexsha_after + ".." + hexsha_before) # diffログを"s"に入れる - lines = s.splitlines() # 行ごと(改行判定(split)もして)リスト化 - - search_flag = "False" - search = [] - for line in lines: # 行ごとにまわす - if line.startswith("+") or line.startswith("-"): # もしも行の先頭が"+"or"-""の時... - # if "@" in line: # もしも"@"が含まれていた時... - search.append(line) - search_flag = "True" - - if search_flag: - print("\n--- " + str(commit_no+1) + " commit .. " + str(commit_no) + " commit ---\n") - for list in search: #ログで見やすく改行するためのfor文 - print(list) - -def run(repo): - sys.stdout = open('./log/diff.log',"w+", encoding="utf_8_sig") # 標準出力をdiff.logに変更 - - sum_commits = repo.git.rev_list('--count', 'HEAD') # コミットの総数 - commit_count = 0 - hexsha_after = "HEAD" # 差分取得用のハッシュ値(親) - - with tqdm(total=int(sum_commits), desc='diff.log') as pbar: # プログレスバーの設定 - for commit in repo.iter_commits(): - commit_no = int(sum_commits) - commit_count - - if commit_count != 0: - # print(repo.git.diff(hexsha + ".." + commit.hexsha)) # ファイルの差分を取得 - - search_lines(repo, hexsha_after, commit.hexsha, commit_no) # 変更行から文字を検索し、その行を抜き出す - - hexsha_after = commit.hexsha - commit_count += 1 - pbar.update(1) # プログレスバーの進捗率を更新 - - search_lines(repo, hexsha_after, "4b825dc642cb6eb9a060e54bf8d69288fbee4904", 0) # 最初のコミットの差分 - - sys.stdout = sys.__stdout__ # 標準出力をコンソールにもどす \ No newline at end of file diff --git a/cmd_help.py b/cmd_help.py deleted file mode 100644 index 0a0267d..0000000 --- a/cmd_help.py +++ /dev/null @@ -1,10 +0,0 @@ -# help - -def run(): - print("help : コマンド一覧を表示") - print("clone: リポジトリをクローン") - print("log : ログを確認") - print("diff : ファイルの差分を確認") - print("plot : グラフを描画") - print("message:コミットメッセージを解析") - print("exit : 終了") \ No newline at end of file diff --git a/cmd_log.py b/cmd_log.py deleted file mode 100644 index dafdb17..0000000 --- a/cmd_log.py +++ /dev/null @@ -1,127 +0,0 @@ -# log - -import csv -from tqdm import tqdm - -import contributor as con - -# コントリビュータの追加した行などを更新 -def add_con_lines(c, insertions, deletions): # c:contributors - c.add_insertions(insertions) # 追加した行 - c.add_deletions(deletions) # 削除した行 - -# コントリビュータの更新 -def set_contributor(c, author, insertions, deletions, commit): # c:contributors - # リストの重複を確認して追加 - i = 0 - for j in range(len(c)): - # authorが既に存在するか確認 - if author in c[i].get_name(): - c[i].add_commit_count(1) - add_con_lines(c[i], insertions, deletions) - c[i].set_first_commit(commit.committed_datetime.strftime('%Y-%m-%d')) - break - i += 1 - # authorがまだ登録されていない場合、追加 - if i == len(c): - c.append(con.Contributor(author, 1)) - add_con_lines(c[i], insertions, deletions) - c[i].set_last_commit(commit.committed_datetime.strftime('%Y-%m-%d')) - -def run(repo): - # log.csv - f_log = open("./log/log.csv","w+", encoding="utf_8_sig", newline='') - csv_log = csv.writer(f_log) - # csvヘッダー追加 - csv_log.writerow([ - 'commit_no', - 'author', - 'committed_datetime', - 'message', - 'hexsha']) - - # contributors.csv - f_con = open("./log/contributors.csv","w+", encoding="utf_8_sig", newline='') - csv_con = csv.writer(f_con) - csv_con.writerow([ - 'Contributor', - 'Commits(%)', - '+lines', - '-lines', - 'First commit', - 'Last commit', - 'Active days', - 'Ranking']) - - sum_commits = repo.git.rev_list('--count', 'HEAD') # コミットの総数 - commit_count = 0 - commit_files = 0 # 変更したファイル数 - sum_insertions = 0 # 追加した行数の合計 - sum_deletions = 0 # 削除した行数の合計 - lines = 0 # 変更行の合計 - merge_count = 0 # マージコミット数 - contributors = [] - with tqdm(total=int(sum_commits), desc='log.csv') as pbar: # プログレスバーの設定 - for commit in repo.iter_commits(): - commit_no = int(sum_commits) - commit_count - insertions = 0 # 追加した行数(コミットごと) - deletions = 0 # 削除した行数(コミットごと) - - file_list = commit.stats.files # ファイルごとの変更履歴(行) - for file_name in file_list: - commit_files += 1 - insertions += file_list.get(file_name).get('insertions') # 追加した行数 - deletions += file_list.get(file_name).get('deletions') # 削除した行数 - lines += file_list.get(file_name).get('lines') # 変更行の合計 - - # log.csvに書き込み - csv_log.writerow([ - commit_no, - commit.author, - commit.committed_datetime.strftime('%Y-%m-%d %H:%M:%S'), - commit.message, - commit.hexsha]) - commit_count += 1 - - # コントリビュータを更新 - set_contributor(contributors, str(commit.author), insertions, deletions, commit) - - sum_insertions += insertions - sum_deletions += deletions - - # マージコミット数を計測 - if commit.message.startswith("Merge"): - merge_count += 1 - - pbar.update(1) # プログレスバーの進捗率を更新 - - rank = 1 - with tqdm(total=len(contributors), desc='contributors.csv') as pbar: - for con in sorted(contributors, key=lambda c: c.commit_count, reverse=True): - # contributors.csvに書き込み - commit_percent = con.get_commit_count() / int(sum_commits) * 100 - csv_con.writerow([ - con.get_name(), - str(con.get_commit_count()) + "({:.1f})".format(commit_percent), - con.get_insertions(), - con.get_deletions(), - con.get_first_commit(), - con.get_last_commit(), - 0, - rank]) - rank += 1 - pbar.update(1) - - f_log.close() - f_con.close() - - print("コミット数:" + sum_commits) - print("マージコミット数:" + str(merge_count)) - print("変更したファイル数(のべ):" + str(commit_files)) - print("・追加した行数:" + str(sum_insertions)) - print("・削除した行数:" + str(sum_deletions)) - print("・変更行の和 :" + str(lines)) - print("・変更行の差 :" + str(sum_insertions - sum_deletions)) - print("コントリビュータ:" + str(len(contributors))) - for contributor in sorted(contributors, key=lambda c: c.commit_count, reverse=True): - print(contributor) \ No newline at end of file diff --git a/cmd_message.py b/cmd_message.py deleted file mode 100644 index f940c8e..0000000 --- a/cmd_message.py +++ /dev/null @@ -1,354 +0,0 @@ -import MeCab -from wordcloud import WordCloud -import collections -import csv as c -from tqdm import tqdm -import seaborn as sns -import matplotlib.pyplot as plt -import re - - -def _mecab_wakati(text): - # 形態素解析を行う(分かち書き) - wakati_tagger = MeCab.Tagger("-Owakati") # 分かち書き - parse = wakati_tagger.parse(text) - return parse - - -def _mecab(text): - # 形態素解析を行い品詞リストを返す - tagger = MeCab.Tagger() - tagger.parse("") - node = tagger.parseToNode(text) - - node_list = [] - while node: - # 例: ['吾輩', '名詞', '代名詞', '一般', '*', '*', '*', '吾輩', 'ワガハイ', 'ワガハイ'] - node_list.append([node.surface]+node.feature.split(",")) - node = node.next - node_list = node_list[1:-1] # BOS/EOSタグを除外 - - return node_list - - -# キーワード解析 -def keyword_analy(text): - key_out = [] - key_list = ["ように", "修正", "追加", "削除", "作成", "設定", "保存", - "変更", "編集", "更新", "整理", "調整", "実装", "表示", "化"] - for key in key_list: - if key in text: - key_out.append(key) - return key_out - - -class WordCloudGenerator: - """ - WordCloud - """ - out_file_name = "" - - def __init__(self, font_path, background_color, width, height, collocations, - stopwords, max_words, regexp): - """ - 出力パラメータ初期化 - """ - self.font_path = font_path - self.background_color = background_color - self.width = width - self.height = height - self.collocations = collocations - self.stopwords = stopwords - self.max_words = max_words - self.regexp = regexp - - def wordcloud_draw(self, parse): - """ - wordcloud画像を出力 - @param - parse 形態素解析結果 - """ - self.wordcloud = WordCloud(font_path=self.font_path, background_color=self.background_color, width=self.width, height=self.height, - collocations=self.collocations, stopwords=self.stopwords, max_words=self.max_words, regexp=self.regexp, repeat=False) - self.wordcloud.generate(parse) - self.wordcloud.to_file(self.out_file_name) - - def frequency_count(self, wakati_text): - """ - 単語の頻出頻度算出 - @param - wakati_text str 分かち書きテキスト - """ - words = wakati_text.split(" ") - words = [word for word in words if word not in self.stopwords] - word_freq = collections.Counter(words) - return word_freq - - def frequency_count_jp(self, wakati_text): - """ - 日本語の単語頻出頻度算出 - @param - wakati_text str 分かち書きテキスト - """ - words = wakati_text.split(" ") - compile_words = re.compile('[!"#$%&\'\\\\()*+,-./:;<=>?@[\\]^_`{|}~「」〔〕“”〈〉『』【】&*・()$#@。、?!`+¥%]') - compile_abc_123 = re.compile(r'[a-zA-Z0-90-9]') - words_jp = [] - for word in words: - if not bool(compile_words.search(word)): - if not bool(compile_abc_123.search(word)): - words_jp.append(word) - word_freq = collections.Counter(words_jp) - return word_freq - - -def _get_all_commit_message(repo): - """ - すべてのcommit messageを取得する - """ - all_commit_message = "" - with open("log/eliminate_message.txt", "w", encoding="utf-8") as f: - for commit in repo.iter_commits(): - # Mergeから始まるcommit messageは除外 - if not commit.message.startswith('Merge'): - all_commit_message += commit.message - - try: - f.write(commit.author) - except TypeError: - pass - f.write(","+commit.message+"\n") - return all_commit_message - - -def _get_commit_message_by_author(repo, author): - """ - 指定したauthorのcommit messageを取得する - """ - commit_message = "" - for commit in repo.iter_commits(): - if commit.author == author: - # Mergeから始まるcommit messageは除外 - if not commit.message.startswith('Merge'): - commit_message += commit.message - return commit_message - - -def _wordcloud_all_messages(repo, wordCloudGenerator): - """ - すべてのcommit messageでwordcloudを作成する - """ - - # 入力テキストファイル - OUT_FILE_NAME = "pic/wordcloud_message.png" - - # 形態素解析 - text = _get_all_commit_message(repo) - mecab_all = _mecab(text) # 形態素解析 - - # 名詞及び名詞連結を取得# - """ - 名詞連結は,現状うまく動かないので,一旦コメントアウト - """ - # mecab_linking_noun = [] - # for m in range(len(mecab_all)-1): - # if mecab_all[m][1] == "名詞" and mecab_all[m+1][1] == "名詞": - # mecab_linking_noun.append( - # mecab_all[m][0]+mecab_all[m+1][0]) - # elif mecab_all[m][1] == "名詞": - # mecab_linking_noun.append(mecab_all[m][0]) - # else: - # pass - - mecab_only_noun = [m[0] for m in mecab_all if m[1] == "名詞"] # 名詞のみ取得 - wakati = " ".join(mecab_only_noun) # 分かち書き - - wordCloudGenerator.out_file_name = OUT_FILE_NAME # 出力ファイル名 - wordCloudGenerator.wordcloud_draw(wakati) # 出力 - - print(f"{wordCloudGenerator.out_file_name}に画像を出力しました") - - print() - - -def _wordcloud_by_author(repo, wordCloudGenerator): - """ - authorごとにwordcloudを作成する - """ - - # 入力テキストファイル - OUT_FILE_NAME = "pic/wordcloud_message_author/{}.png" - - # すべてのauthorを取得 #この方法はちょっと時間がかかるかも.最適化の余地あり. - authors = set() - for commit in repo.iter_commits(): - authors.add(commit.author) - - # 各authorのcommit messageを取得 - authors_text = dict() - for author in authors: - # authorの名前は一緒だが,メアドが違う場合があるとき,同じauthorとみなしてmessageを結合する - if author.name in authors_text: - authors_text[author.name] += _get_commit_message_by_author( - repo, author) - else: - authors_text[author.name] = _get_commit_message_by_author( - repo, author) - - for author, text in authors_text.items(): - # 形態素解析 - mecab_all = _mecab(text) # 形態素解析 - - # リストが空の場合はスキップ - if len(mecab_all) == 0: - continue - - # 名詞及び名詞連結を取得# - """ - 名詞連結は,現状うまく動かないので,一旦コメントアウト - """ - # mecab_linking_noun = [] - # for m in range(len(mecab_all)-1): - # if mecab_all[m][1] == "名詞" and mecab_all[m+1][1] == "名詞": - # mecab_linking_noun.append( - # mecab_all[m][0]+mecab_all[m+1][0]) - # elif mecab_all[m][1] == "名詞": - # mecab_linking_noun.append(mecab_all[m][0]) - # else: - # pass - - mecab_only_noun = [m[0] for m in mecab_all if m[1] == "名詞"] # 名詞のみ取得 - wakati = " ".join(mecab_only_noun) # 分かち書き - - wordCloudGenerator.out_file_name = OUT_FILE_NAME.format(author) # 出力ファイル名 - - wordCloudGenerator.wordcloud_draw(wakati) # 出力 - - print(f"{wordCloudGenerator.out_file_name}に画像を出力しました") - - print("すべてのcontributorのwordcloudを出力しました") - print() - - -def run(repo): - # message.csv - f = open("./log/message.csv", "w+", encoding="utf_8_sig", newline='') - csv = c.writer(f) - # csvヘッダー追加 - csv.writerow([ - 'commit_no', - 'message', - 'len', - 'key_flag', - 'keyword', - 'marp_flag' - 'morpheme']) - - sum_commits = repo.git.rev_list('--count', 'HEAD') # コミットの総数 - commit_count = 0 - sum_message_len = 0 # メッセージの文字数合計 - key_match_count = 0 # キーワードの一致回数合計 - # commit message を取得 - with tqdm(total=int(sum_commits), desc='message.csv') as pbar: # プログレスバーの設定 - for commit in repo.iter_commits(): - commit_no = int(sum_commits) - commit_count - message_len = int(len(commit.message)) - 1 - sum_message_len += message_len - keyword = keyword_analy(commit.message) - key_flag = len(keyword) - if key_flag == 0: - keyword = "none" - else: - key_match_count += 1 - - # message.csvに書き込み - csv.writerow([ - commit_no, - commit.message, - message_len, - key_flag, - keyword, - 0, - "none"]) - - commit_count += 1 - - pbar.update(1) # プログレスバーの進捗率を更新 - - """ - wordcloud生成処理 - """ - #### パラメータ #### - STOP_WORDS = [" ", " "] # ストップワード - MAX_WORDS = 2000 # 出力個数の上限 - WIDTH = 500 # 出力画像の幅 - HEIGHT = 500 # 出力画像の高さ - FONT_FILE = "font/ipaexg.ttf" # フォントファイルのパス - - wordCloudGenerator = WordCloudGenerator(font_path=FONT_FILE, background_color="white", width=WIDTH, height=HEIGHT, collocations=False, - stopwords=STOP_WORDS, max_words=MAX_WORDS, regexp=r"[\w']+") # WordCloud初期化 - - _wordcloud_by_author(repo, wordCloudGenerator) # authorごとにwordcloudを作成 - # _wordcloud_all_messages(repo, wordCloudGenerator) # 全メッセージをwordcloudにして出力 - - # 単語の頻出頻度 - wordCloudGenerator.out_file_name = "./pic/word_frequency.png" - - """マージ前の処理と同じはず""" - mecab_all = _mecab(_get_all_commit_message(repo)) # 形態素解析 - mecab_only_noun = [m[0] for m in mecab_all if m[1] == "名詞"] # 名詞のみ取得 - wakati = " ".join(mecab_only_noun) # 分かち書き - - frequency_words = wordCloudGenerator.frequency_count_jp(wakati).most_common(30) - sns.set(context="talk", font='Yu Gothic') - fig = plt.subplots(figsize=(18, 8)) - sns.countplot(y=mecab_only_noun, order=[i[0] for i in frequency_words]) - plt.subplots_adjust(left=0.175, right=0.95, bottom=0.12, top=0.95) - plt.savefig("pic/frequency_words.png") - print("pic/frequency_words.pngに画像を出力しました") - - print("---メッセージ解析結果---") - print("総メッセージ数:" + sum_commits) - print("文字数の平均:{:.1f}".format(sum_message_len/int(sum_commits))) - print("キーワード一致回数:" + str(key_match_count)) - print() - - f.close() - - -if __name__ == "__main__": - OUT_FILE_NAME = "pic/wordcloud_message.png" - - TEXT = "吾輩は吾輩である.名前はスーパー吾輩である.Yes, I am wagahai." - - mecab_all = _mecab(TEXT) # 形態素解析 - - # 名詞及び名詞連結を取得# - """ - 名詞連結は,現状うまく動かないので,一旦コメントアウト - """ - # mecab_linking_noun = [] - # for m in range(len(mecab_all)-1): - # if mecab_all[m][1] == "名詞" and mecab_all[m+1][1] == "名詞": - # mecab_linking_noun.append( - # mecab_all[m][0]+mecab_all[m+1][0]) - # elif mecab_all[m][1] == "名詞": - # mecab_linking_noun.append(mecab_all[m][0]) - # else: - # pass - - mecab_only_noun = [m[0] for m in mecab_all if m[1] == "名詞"] # 名詞のみ取得 - - #### パラメータ #### - STOP_WORDS = [" "] # ストップワード - MAX_WORDS = 2000 # 出力個数の上限 - WIDTH = 500 # 出力画像の幅 - HEIGHT = 500 # 出力画像の高さ - FONT_FILE = "data/ipaexg.ttf" # フォントファイルのパス - - wakati = " ".join(mecab_only_noun) # 分かち書き - - wordCloudGenerator = WordCloudGenerator(font_path=FONT_FILE, background_color="white", width=WIDTH, height=HEIGHT, collocations=False, - stopwords=STOP_WORDS, max_words=MAX_WORDS, regexp=r"[\w']+") # WordCloud初期化 - wordCloudGenerator.out_file_name = OUT_FILE_NAME # 出力ファイル名 - wordCloudGenerator.wordcloud_draw(wakati) # 出力 diff --git a/cmd_plot.py b/cmd_plot.py deleted file mode 100644 index ccc3e7b..0000000 --- a/cmd_plot.py +++ /dev/null @@ -1,236 +0,0 @@ -# plot - -import matplotlib.pyplot as plt -import calendar -import datetime -from datetime import datetime as dt -import csv -import seaborn as sns -import pandas as pd -from tqdm import tqdm - -# 現在の年を取得 -def get_year(): - currentDateTime = datetime.datetime.now() - date = currentDateTime.date() - year = date.strftime("%Y") - return int(year) - -# 曜日を取得 -def get_dow(day): # day of week - dow = datetime.datetime.strptime(day, '%Y-%m-%d').strftime('%a') - return dow - -# 曜日を数字で取得 -def get_dow_no(dow): - if (dow == "Sun"): return 0 - elif (dow == "Mon"): return 1 - elif (dow == "Tue"): return 2 - elif (dow == "Wed"): return 3 - elif (dow == "Thu"): return 4 - elif (dow == "Fri"): return 5 - elif (dow == "Sat"): return 6 - -# 月を英語の文字列で取得 -def get_month_en(day): # day of week - month_en = datetime.datetime.strptime(day, '%Y-%m-%d').strftime('%b') - return month_en - -# 月が変わった(week+0.5)を取得 -def get_month_change_point(year_dayslist): - month_point = [] # 月が替わるタイミングのweek - - day_count = 0 - week = 0 - for month in range(12): - month_point.append(week+0.5) - for i in range(calendar.monthrange(int(get_year()), month+1)[1]): - dow = get_dow(year_dayslist[day_count]) - day_count += 1 - if dow == "Sat": - week += 1 - - return month_point - -# 現在の年の日数を取得 -def calc_days(): - year_days = 0 - for i in range(12): - year_days += calendar.monthrange(get_year(), i+1)[1] - return year_days - -# 現在の年の日付をリストで取得 -def get_year_dayslist(): - year_dayslist = [] - for month in range(12): - for day in range(calendar.monthrange(int(get_year()), month+1)[1]): - year_dayslist.append("{:<4d}-{:0>2d}-{:0>2d}".format(get_year(), month+1, day+1)) - return year_dayslist - -# 現在の年のコミットデータを作成 -def set_commit_calendar( year_days, year_dayslist, committed_year, committed_datetimes): - f = open("./log/commit_calendar.csv","w+", encoding="utf_8_sig", newline='') - csv_writer = csv.writer(f) - csv_writer.writerow([ - 'year', - 'month', - 'month_en', - 'day', - 'dow_no', - 'dow', - 'week', - 'commit']) # csvヘッダー追加 - - day_count = 0 - week = 0 - # 現在の年の日ごとコミット数を計算 - with tqdm(total=year_days, desc='commit_calendar.csv') as pbar: # プログレスバーの設定 - for month in range(12): - for day in range(calendar.monthrange(int(get_year()), month+1)[1]): - commit_count = committed_datetimes.count(year_dayslist[day_count]) - dow = get_dow(year_dayslist[day_count]) - dow_no = get_dow_no(dow) - month_en = get_month_en(year_dayslist[day_count]) - # committed_year.setdefault(year_dayslist[day_count], committed_datetimes.count(year_dayslist[day_count])) - csv_writer.writerow([ - get_year(), - month+1, - month_en, - day+1, - dow_no, - dow, - week, - commit_count]) # csvファイルに書き込み - day_count += 1 - - if dow == "Sat": - week += 1 - - pbar.update(1) # プログレスバーの進捗率を更新 - - f.close() - -# 日付差の日数を算出(リストに最終日も含めたいので、+1) -def get_dayslist(committed_datetimes, sum_commits): - dayslist = [] # 最初から最後のコミット間の日付リスト - first_commit = committed_datetimes[int(sum_commits)-1] - last_commit = committed_datetimes[0] - # 日付条件の設定 - strdt = dt.strptime(first_commit, '%Y-%m-%d').date() # 開始日 - enddt = dt.strptime(last_commit, '%Y-%m-%d').date() # 終了日 - # 日付差の日数を算出(リストに最終日も含めたいので、+1しています) - days_num = (enddt - strdt).days + 1 - - for i in range(days_num): - dayslist.append(strdt + datetime.timedelta(days=i)) # 日付差のリスト - - return dayslist - -# コミットの合計値を日付順で計算し、csvに出力 -def set_commit_transition(committed_datetimes, dayslist): - f = open("./log/commit_transition.csv","w+", encoding="utf_8_sig", newline='') - csv_writer = csv.writer(f) - csv_writer.writerow([ - 'day', - 'commit', - 'sum commit']) # csvヘッダー追加 - - day_commitlist = [] - sum_commitlist = [] - sum_commit = 0 - # 現在の年の日ごとコミット数を計算 - with tqdm(total=len(dayslist), desc='commit_transition.csv') as pbar: # プログレスバーの設定 - for day in dayslist: # コミットの合計値を日付順で計算 - day_commits = committed_datetimes.count(str(day)) - day_commitlist.append(day_commits) - sum_commit += day_commits - sum_commitlist.append(sum_commit) - - csv_writer.writerow([ - day, - day_commits, - sum_commit]) # csvファイルに書き込み - - pbar.update(1) # プログレスバーの進捗率を更新 - - f.close() - return day_commitlist, sum_commitlist - -def run(repo): - - # ------------ - # --- fig2 --- - # ------------ - - sum_commits = repo.git.rev_list('--count', 'HEAD') # コミットの総数 - # コミット履歴を取得 - committed_datetimes = [] # コミットした日付リスト - for commit in repo.iter_commits(): - committed_datetimes.append(commit.committed_datetime.strftime('%Y-%m-%d')) - - dayslist = get_dayslist(committed_datetimes, sum_commits) # 日付差の日数を算出 - day_commitlist, sum_commitlist = set_commit_transition(committed_datetimes, dayslist) # コミットの合計値を日付順で計算 - - # ------------ - # --- fig1 --- - # ------------ - - year_days = calc_days() # 現在の年の日数 - year_dayslist = get_year_dayslist() # 現在の年の日付リスト - committed_year = {} # 現在の年の日ごとコミット数 - mcp = get_month_change_point(year_dayslist) # 月が変わった(week+0.5)を取得 - - # コミットデータを作成 - set_commit_calendar(year_days, year_dayslist, committed_year, committed_datetimes) - - # ------------ - # --- plot --- - # ------------ - - # --- fig1 --- - - # CSV読み込み - df1 = pd.read_csv("./log/commit_calendar.csv",sep=",") - df1.columns = ['year','month','month_en','day','dow_no','dow', 'week', 'commit'] - df1 = df1.pivot('dow_no','week','commit') - - fig1, ax1 = plt.subplots(figsize=(10, 3)) # 10対3のプロットを作成 - - sns.heatmap( - df1, - cmap="Greens", - linewidths=.25, - square=True, - cbar=False) - - ax1.set_title(str(get_year()) + " year (" + repo.git.rev_list('--count', 'HEAD') + " commit)") - ax1.set_xlabel('') - ax1.set_ylabel('') - ax1.set_yticks([1.5, 3.5, 5.5]) - ax1.set_yticklabels(['Mon', 'Wed', 'Fri'], rotation=0) - ax1.set_xticks([mcp[0], mcp[1], mcp[2], mcp[3], mcp[4], mcp[5], mcp[6], mcp[7], mcp[8], mcp[9], mcp[10], mcp[11]]) - ax1.set_xticklabels(['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], rotation=0) - - fig1.savefig("pic/commit_calendar.png", tight_layout=True) # グラフを画像で保存 - - # --- fig2 --- - - fig2, ax2 = plt.subplots(figsize=(12, 7)) - - ax2.plot(dayslist, sum_commitlist, label="sum", linestyle="-", marker="", color="lightseagreen") - ax2.plot(dayslist, day_commitlist, label="1day", linestyle="-", marker="", color="lightcoral") - ax2.grid(b=True, which='major', color='gray', linestyle='-', linewidth=0.5, alpha=0.3) - ax2.minorticks_on() - ax2.spines['right'].set_visible(False) - ax2.spines['top'].set_visible(False) - ax2.spines['bottom'].set_visible(False) - ax2.spines['left'].set_visible(False) - ax2.set_title("commit transition") - ax2.set_xlabel('date') - ax2.xaxis.set_tick_params(rotation=10) - ax2.set_ylabel('commits') - ax2.legend() - ax2.fill_between(dayslist, 0, day_commitlist, facecolor='lightcoral', alpha=0.3) - ax2.fill_between(dayslist, day_commitlist, sum_commitlist, facecolor='lightseagreen', alpha=0.3) - - fig2.savefig("pic/commit_transition.png") \ No newline at end of file diff --git a/cmd_seek.py b/cmd_seek.py deleted file mode 100644 index 058f7c9..0000000 --- a/cmd_seek.py +++ /dev/null @@ -1,49 +0,0 @@ -# コマンド処理 - -import cmd_help -import cmd_clone -import cmd_log -import cmd_diff -import cmd_plot -import cmd_message - - -def run(repo, cmd): - # help - if (cmd == "help"): - cmd_help.run() - return True - - # clone - elif (cmd == "clone"): - cmd_clone.run(1) - return True - - # log - elif (cmd == "log"): - cmd_log.run(repo) - return True - - # diff - elif (cmd == "diff"): - cmd_diff.run(repo) - return True - - # plot - elif (cmd == "plot"): - cmd_plot.run(repo) - return True - - # message - elif(cmd == "message"): - cmd_message.run(repo) - return True - - # exit - elif (cmd == "exit()" or cmd == "exit"): - return False - - # 例外 - else: - print("そのコマンドは使用できません") - return True diff --git a/color.py b/color.py deleted file mode 100644 index ba6dc40..0000000 --- a/color.py +++ /dev/null @@ -1,48 +0,0 @@ -# 色 - -BLACK = '\033[30m' # (文字)黒 -RED = '\033[31m' # (文字)赤 -GREEN = '\033[32m' # (文字)緑 -YELLOW = '\033[33m' # (文字)黄 -BLUE = '\033[34m' # (文字)青 -MAGENTA = '\033[35m' # (文字)マゼンタ -CYAN = '\033[36m' # (文字)シアン -WHITE = '\033[37m' # (文字)白 -COLOR_DEFAULT = '\033[39m' # 文字色をデフォルトに戻す -BOLD = '\033[1m' # 太字 -UNDERLINE = '\033[4m' # 下線 -INVISIBLE = '\033[08m' # 不可視 -REVERCE = '\033[07m' # 文字色と背景色を反転 -BG_BLACK = '\033[40m' # (背景)黒 -BG_RED = '\033[41m' # (背景)赤 -BG_GREEN = '\033[42m' # (背景)緑 -BG_YELLOW = '\033[43m' # (背景)黄 -BG_BLUE = '\033[44m' # (背景)青 -BG_MAGENTA = '\033[45m' # (背景)マゼンタ -BG_CYAN = '\033[46m' # (背景)シアン -BG_WHITE = '\033[47m' # (背景)白 -BG_DEFAULT = '\033[49m' # 背景色をデフォルトに戻す -RESET = '\033[0m' # 全てリセット - -if __name__ == "__main__": - print(f'黒:{BLACK}●ABC{RESET}') - print(f'赤:{RED}●ABC{RESET}') - print(f'緑:{GREEN}●ABC{RESET}') - print(f'黄:{YELLOW}●ABC{RESET}') - print(f'青:{BLUE}●ABC{RESET}') - print(f'マゼンタ:{MAGENTA}●ABC{RESET}') - print(f'シアン:{CYAN}●ABC{RESET}') - print(f'白:{WHITE}●ABC{RESET}') - print(f'下線:{UNDERLINE}●ABC{RESET}') - print(f'太字:{BOLD}●ABC{RESET}') - print(f'不可視:{INVISIBLE}●ABC{RESET}') - print(f'反転:{REVERCE}●ABC{RESET}') - print(f'背景黒:{BG_BLACK}●ABC{RESET}') - print(f'背景赤:{BG_RED}●ABC{RESET}') - print(f'背景緑:{BG_GREEN}●ABC{RESET}') - print(f'背景黄:{BG_YELLOW}●ABC{RESET}') - print(f'背景青:{BG_BLUE}●ABC{RESET}') - print(f'背景マゼンタ:{BG_MAGENTA}●ABC{RESET}') - print(f'背景シアン:{BG_CYAN}●ABC{RESET}') - print(f'背景白:{BG_WHITE}●ABC{RESET}') - print(f'文字赤+背景緑:{RED}{BG_GREEN}●ABC{RESET}') # 文字色と背景色を変える diff --git a/contributor.py b/contributor.py deleted file mode 100644 index 027213b..0000000 --- a/contributor.py +++ /dev/null @@ -1,87 +0,0 @@ -# contributor - -# コントリビュータクラス -class Contributor: - def __init__(self, name, commit_count): - self.name = name - self.commit_count = commit_count - self.insertions = 0 # 追加した行数 - self.deletions = 0 # 削除した行数 - self.first_commit = "" # 最初のコミットの日時 - self.last_commit = "" # 最後のコミットの日時 - - # 情報のprint結果を定義 - def __repr__(self): - return "commit: {:>4d} 【 {:s} 】".format(self.commit_count, str(self.name)) - - # ----------- - # --- set --- - # ----------- - - # nameを更新 - def set_name(self, name): - self.name = name - - # commit_countを更新 - def set_commit_count(self, commit_count): - self.commit_count = commit_count - - # insertionsを更新 - def set_insertions(self, insertions): - self.insertions = insertions - - # deletionsを更新 - def set_insertions(self, deletions): - self.deletions = deletions - - # 最初のコミットの日時更新 - def set_first_commit(self, commit_day): - self.first_commit = commit_day - - # 最後のコミットの日時更新 - def set_last_commit(self, commit_day): - self.last_commit = commit_day - - # ----------- - # --- get --- - # ----------- - - # nameを取得 - def get_name(self): - return self.name - - # commit_countを取得 - def get_commit_count(self): - return self.commit_count - - # commit_countを取得 - def get_insertions(self): - return self.insertions - - # commit_countを取得 - def get_deletions(self): - return self.deletions - - # 最初のコミットの日時取得 - def get_first_commit(self): - return self.first_commit - - # 最後のコミットの日時取得 - def get_last_commit(self): - return self.last_commit - - # ----------- - # --- add --- - # ----------- - - # commit_countにnumを足す - def add_commit_count(self, num): - self.commit_count += num - - # insertionsを足す - def add_insertions(self, insertions): - self.insertions += insertions - - # deletionsを足す - def add_deletions(self, deletions): - self.deletions += deletions \ No newline at end of file diff --git a/font/IPA_Font_License_Agreement_v1.0.txt b/font/IPA_Font_License_Agreement_v1.0.txt new file mode 100644 index 0000000..fe8db24 --- /dev/null +++ b/font/IPA_Font_License_Agreement_v1.0.txt @@ -0,0 +1,117 @@ +-------------------------------------------------- +IPA Font License Agreement v1.0 +-------------------------------------------------- + +IPAフォントライセンスv1.0 + +許諾者は、この使用許諾(以下「本契約」といいます。)に定める条件の下で、許諾プログラム(1条に定義するところによります。)を提供します。受領者(1条に定義するところによります。)が、許諾プログラムを使用し、複製し、または頒布する行為、その他、本契約に定める権利の利用を行った場合、受領者は本契約に同意したものと見なします。 + + +第1条 用語の定義 + +本契約において、次の各号に掲げる用語は、当該各号に定めるところによります。 + +1.「デジタル・フォント・プログラム」とは、フォントを含み、レンダリングしまたは表示するために用いられるコンピュータ・プログラムをいいます。 +2.「許諾プログラム」とは、許諾者が本契約の下で許諾するデジタル・フォント・プログラムをいいます。 +3.「派生プログラム」とは、許諾プログラムの一部または全部を、改変し、加除修正等し、入れ替え、その他翻案したデジタル・フォント・プログラムをいい、許諾プログラムの一部もしくは全部から文字情報を取り出し、またはデジタル・ドキュメント・ファイルからエンベッドされたフォントを取り出し、取り出された文字情報をそのまま、または改変をなして新たなデジタル・フォント・プログラムとして製作されたものを含みます。 +4.「デジタル・コンテンツ」とは、デジタル・データ形式によってエンド・ユーザに提供される制作物のことをいい、動画・静止画等の映像コンテンツおよびテレビ番組等の放送コンテンツ、ならびに文字テキスト、画像、図形等を含んで構成された制作物を含みます。 +5.「デジタル・ドキュメント・ファイル」とは、PDFファイルその他、各種ソフトウェア・プログラムによって製作されたデジタル・コンテンツであって、その中にフォントを表示するために許諾プログラムの全部または一部が埋め込まれた(エンベッドされた)ものをいいます。フォントが「エンベッドされた」とは、当該フォントが埋め込まれた特定の「デジタル・ドキュメント・ファイル」においてのみ表示されるために使用されている状態を指し、その特定の「デジタル・ドキュメント・ファイル」以外でフォントを表示するために使用できるデジタル・フォント・プログラムに含まれている場合と区別されます。 +6.「コンピュータ」とは、本契約においては、サーバを含みます。 +7.「複製その他の利用」とは、複製、譲渡、頒布、貸与、公衆送信、上映、展示、翻案その他の利用をいいます。 +8.「受領者」とは、許諾プログラムを本契約の下で受領した人をいい、受領者から許諾プログラムを受領した人を含みます。 + +第2条 使用許諾の付与 + +許諾者は受領者に対し、本契約の条項に従い、すべての国で、許諾プログラムを使用することを許諾します。ただし、許諾プログラムに存在する一切の権利はすべて許諾者が保有しています。本契約は、本契約で明示的に定められている場合を除き、いかなる意味においても、許諾者が保有する許諾プログラムに関する一切の権利および、いかなる商標、商号、もしくはサービス・マークに関する権利をも受領者に移転するものではありません。 + +1.受領者は本契約に定める条件に従い、許諾プログラムを任意の数のコンピュータにインストールし、当該コンピュータで使用することができます。 +2.受領者はコンピュータにインストールされた許諾プログラムをそのまま、または改変を行ったうえで、印刷物およびデジタル・コンテンツにおいて、文字テキスト表現等として使用することができます。 +3.受領者は前項の定めに従い作成した印刷物およびデジタル・コンテンツにつき、その商用・非商用の別、および放送、通信、各種記録メディアなどの媒体の形式を問わず、複製その他の利用をすることができます。 +4.受領者がデジタル・ドキュメント・ファイルからエンベッドされたフォントを取り出して派生プログラムを作成した場合には、かかる派生プログラムは本契約に定める条件に従う必要があります。 +5.許諾プログラムのエンベッドされたフォントがデジタル・ドキュメント・ファイル内のデジタル・コンテンツをレンダリングするためにのみ使用される場合において、受領者が当該デジタル・ドキュメント・ファイルを複製その他の利用をする場合には、受領者はかかる行為に関しては本契約の下ではいかなる義務をも負いません。 +6.受領者は、3条2項の定めに従い、商用・非商用を問わず、許諾プログラムをそのままの状態で改変することなく複製して第三者への譲渡し、公衆送信し、その他の方法で再配布することができます(以下、「再配布」といいます。)。 +7.受領者は、上記の許諾プログラムについて定められた条件と同様の条件に従って、派生プログラムを作成し、使用し、複製し、再配布することができます。ただし、受領者が派生プログラムを再配布する場合には、3条1項の定めに従うものとします。 + +第3条 制限 + +前条により付与された使用許諾は、以下の制限に服します。 + +1.派生プログラムが前条4項及び7項に基づき再配布される場合には、以下の全ての条件を満たさなければなりません。 + (1)派生プログラムを再配布する際には、下記もまた、当該派生プログラムと一緒に再配布され、オンラインで提供され、または、郵送費・媒体及び取扱手数料の合計を超えない実費と引き換えに媒体を郵送する方法により提供されなければなりません。 +  (a)派生プログラムの写し; および +  (b)派生プログラムを作成する過程でフォント開発プログラムによって作成された追加のファイルであって派生プログラムをさらに加工するにあたって利用できるファイルが存在すれば、当該ファイル + (2)派生プログラムの受領者が、派生プログラムを、このライセンスの下で最初にリリースされた許諾プログラム(以下、「オリジナル・プログラム」といいます。)に置き換えることができる方法を再配布するものとします。かかる方法は、オリジナル・ファイルからの差分ファイルの提供、または、派生プログラムをオリジナル・プログラムに置き換える方法を示す指示の提供などが考えられます。 + (3)派生プログラムを、本契約書に定められた条件の下でライセンスしなければなりません。 + (4)派生プログラムのプログラム名、フォント名またはファイル名として、許諾プログラムが用いているのと同一の名称、またはこれを含む名称を使用してはなりません。 + (5)本項の要件を満たすためにオンラインで提供し、または媒体を郵送する方法で提供されるものは、その提供を希望するいかなる者によっても提供が可能です。 +2.受領者が前条6項に基づき許諾プログラムを再配布する場合には、以下の全ての条件を満たさなければなりません。 + (1)許諾プログラムの名称を変更してはなりません。 + (2)許諾プログラムに加工その他の改変を加えてはなりません。 + (3)本契約の写しを許諾プログラムに添付しなければなりません。 +3.許諾プログラムは、現状有姿で提供されており、許諾プログラムまたは派生プログラムについて、許諾者は一切の明示または黙示の保証(権利の所在、非侵害、商品性、特定目的への適合性を含むがこれに限られません)を行いません。いかなる場合にも、その原因を問わず、契約上の責任か厳格責任か過失その他の不法行為責任かにかかわらず、また事前に通知されたか否かにかかわらず、許諾者は、許諾プログラムまたは派生プログラムのインストール、使用、複製その他の利用または本契約上の権利の行使によって生じた一切の損害(直接・間接・付随的・特別・拡大・懲罰的または結果的損害)(商品またはサービスの代替品の調達、システム障害から生じた損害、現存するデータまたはプログラムの紛失または破損、逸失利益を含むがこれに限られません)について責任を負いません。 +4.許諾プログラムまたは派生プログラムのインストール、使用、複製その他の利用に関して、許諾者は技術的な質問や問い合わせ等に対する対応その他、いかなるユーザ・サポートをも行う義務を負いません。 + +第4条 契約の終了 + +1.本契約の有効期間は、受領者が許諾プログラムを受領した時に開始し、受領者が許諾プログラムを何らかの方法で保持する限り続くものとします。 +2.前項の定めにかかわらず、受領者が本契約に定める各条項に違反したときは、本契約は、何らの催告を要することなく、自動的に終了し、当該受領者はそれ以後、許諾プログラムおよび派生プログラムを一切使用しまたは複製その他の利用をすることができないものとします。ただし、かかる契約の終了は、当該違反した受領者から許諾プログラムまたは派生プログラムの配布を受けた受領者の権利に影響を及ぼすものではありません。 + +第5条 準拠法 + +1.IPAは、本契約の変更バージョンまたは新しいバージョンを公表することができます。その場合には、受領者は、許諾プログラムまたは派生プログラムの使用、複製その他の利用または再配布にあたり、本契約または変更後の契約のいずれかを選択することができます。その他、上記に記載されていない条項に関しては日本の著作権法および関連法規に従うものとします。 +2.本契約は、日本法に基づき解釈されます。 + + +---------- + +IPA Font License Agreement v1.0 + +The Licensor provides the Licensed Program (as defined in Article 1 below) under the terms of this license agreement (“Agreement”). Any use, reproduction or distribution of the Licensed Program, or any exercise of rights under this Agreement by a Recipient (as defined in Article 1 below) constitutes the Recipient's acceptance of this Agreement. + +Article 1 (Definitions) +1.“Digital Font Program” shall mean a computer program containing, or used to render or display fonts. +2.“Licensed Program” shall mean a Digital Font Program licensed by the Licensor under this Agreement. +3.“Derived Program” shall mean a Digital Font Program created as a result of a modification, addition, deletion, replacement or any other adaptation to or of a part or all of the Licensed Program, and includes a case where a Digital Font Program newly created by retrieving font information from a part or all of the Licensed Program or Embedded Fonts from a Digital Document File with or without modification of the retrieved font information. +4.“Digital Content” shall mean products provided to end users in the form of digital data, including video content, motion and/or still pictures, TV programs or other broadcasting content and products consisting of character text, pictures, photographic images, graphic symbols and/or the like. +5.“Digital Document File” shall mean a PDF file or other Digital Content created by various software programs in which a part or all of the Licensed Program becomes embedded or contained in the file for the display of the font (“Embedded Fonts”). Embedded Fonts are used only in the display of characters in the particular Digital Document File within which they are embedded, and shall be distinguished from those in any Digital Font Program, which may be used for display of characters outside that particular Digital Document File. +6.“Computer” shall include a server in this Agreement. +7.“Reproduction and Other Exploitation” shall mean reproduction, transfer, distribution, lease, public transmission, presentation, exhibition, adaptation and any other exploitation. +8.“Recipient” shall mean anyone who receives the Licensed Program under this Agreement, including one that receives the Licensed Program from a Recipient. + +Article 2 (Grant of License) +The Licensor grants to the Recipient a license to use the Licensed Program in any and all countries in accordance with each of the provisions set forth in this Agreement. However, any and all rights underlying in the Licensed Program shall be held by the Licensor. In no sense is this Agreement intended to transfer any right relating to the Licensed Program held by the Licensor except as specifically set forth herein or any right relating to any trademark, trade name, or service mark to the Recipient. + +1.The Recipient may install the Licensed Program on any number of Computers and use the same in accordance with the provisions set forth in this Agreement. +2.The Recipient may use the Licensed Program, with or without modification in printed materials or in Digital Content as an expression of character texts or the like. +3.The Recipient may conduct Reproduction and Other Exploitation of the printed materials and Digital Content created in accordance with the preceding Paragraph, for commercial or non-commercial purposes and in any form of media including but not limited to broadcasting, communication and various recording media. +4.If any Recipient extracts Embedded Fonts from a Digital Document File to create a Derived Program, such Derived Program shall be subject to the terms of this agreement. +5.If any Recipient performs Reproduction or Other Exploitation of a Digital Document File in which Embedded Fonts of the Licensed Program are used only for rendering the Digital Content within such Digital Document File then such Recipient shall have no further obligations under this Agreement in relation to such actions. +6.The Recipient may reproduce the Licensed Program as is without modification and transfer such copies, publicly transmit or otherwise redistribute the Licensed Program to a third party for commercial or non-commercial purposes (“Redistribute”), in accordance with the provisions set forth in Article 3 Paragraph 2. +7.The Recipient may create, use, reproduce and/or Redistribute a Derived Program under the terms stated above for the Licensed Program: provided, that the Recipient shall follow the provisions set forth in Article 3 Paragraph 1 when Redistributing the Derived Program. + +Article 3 (Restriction) +The license granted in the preceding Article shall be subject to the following restrictions: + +1.If a Derived Program is Redistributed pursuant to Paragraph 4 and 7 of the preceding Article, the following conditions must be met : + (1)The following must be also Redistributed together with the Derived Program, or be made available online or by means of mailing mechanisms in exchange for a cost which does not exceed the total costs of postage, storage medium and handling fees: +  (a)a copy of the Derived Program; and +  (b)any additional file created by the font developing program in the course of creating the Derived Program that can be used for further modification of the Derived Program, if any. + (2)It is required to also Redistribute means to enable recipients of the Derived Program to replace the Derived Program with the Licensed Program first released under this License (the “Original Program”). Such means may be to provide a difference file from the Original Program, or instructions setting out a method to replace the Derived Program with the Original Program. + (3)The Recipient must license the Derived Program under the terms and conditions of this Agreement. + (4)No one may use or include the name of the Licensed Program as a program name, font name or file name of the Derived Program. + (5)Any material to be made available online or by means of mailing a medium to satisfy the requirements of this paragraph may be provided, verbatim, by any party wishing to do so. +2.If the Recipient Redistributes the Licensed Program pursuant to Paragraph 6 of the preceding Article, the Recipient shall meet all of the following conditions: + (1)The Recipient may not change the name of the Licensed Program. + (2)The Recipient may not alter or otherwise modify the Licensed Program. + (3)The Recipient must attach a copy of this Agreement to the Licensed Program. +3.THIS LICENSED PROGRAM IS PROVIDED BY THE LICENSOR “AS IS” AND ANY EXPRESSED OR IMPLIED WARRANTY AS TO THE LICENSED PROGRAM OR ANY DERIVED PROGRAM, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXTENDED, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO; PROCUREMENT OF SUBSTITUTED GOODS OR SERVICE; DAMAGES ARISING FROM SYSTEM FAILURE; LOSS OR CORRUPTION OF EXISTING DATA OR PROGRAM; LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE INSTALLATION, USE, THE REPRODUCTION OR OTHER EXPLOITATION OF THE LICENSED PROGRAM OR ANY DERIVED PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +4.The Licensor is under no obligation to respond to any technical questions or inquiries, or provide any other user support in connection with the installation, use or the Reproduction and Other Exploitation of the Licensed Program or Derived Programs thereof. + +Article 4 (Termination of Agreement) +1.The term of this Agreement shall begin from the time of receipt of the Licensed Program by the Recipient and shall continue as long as the Recipient retains any such Licensed Program in any way. +2.Notwithstanding the provision set forth in the preceding Paragraph, in the event of the breach of any of the provisions set forth in this Agreement by the Recipient, this Agreement shall automatically terminate without any notice. In the case of such termination, the Recipient may not use or conduct Reproduction and Other Exploitation of the Licensed Program or a Derived Program: provided that such termination shall not affect any rights of any other Recipient receiving the Licensed Program or the Derived Program from such Recipient who breached this Agreement. + +Article 5 (Governing Law) +1.IPA may publish revised and/or new versions of this License. In such an event, the Recipient may select either this Agreement or any subsequent version of the Agreement in using, conducting the Reproduction and Other Exploitation of, or Redistributing the Licensed Program or a Derived Program. Other matters not specified above shall be subject to the Copyright Law of Japan and other related laws and regulations of Japan. +2.This Agreement shall be construed under the laws of Japan. + diff --git a/font/ipaexg.ttf b/font/ipaexg.ttf new file mode 100644 index 0000000..811b9c0 --- /dev/null +++ b/font/ipaexg.ttf Binary files differ diff --git a/log/.gitkeep b/log/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.gitkeep diff --git a/main.py b/main.py deleted file mode 100644 index de55568..0000000 --- a/main.py +++ /dev/null @@ -1,35 +0,0 @@ -# main - -import color -import cmd_seek -import cmd_clone -import repo - -# タイトルを表示 -def set_title(): - print(f"{color.CYAN} _____ _____ _ {color.RESET}") - print(f"{color.CYAN}| _ |___ ___ ___ | |_|___ ___ {color.RESET}") - print(f"{color.CYAN}| _| _| . | . || | | | | | _| {color.RESET}") - print(f"{color.CYAN}|_|\__|___| _|___||_|_|_|_|_|_|___| for Py {color.RESET}") - print(f"{color.CYAN} |_| {color.RESET}\n") - -def set_end(): - print(f"\n{color.CYAN}end{color.RESET}\n") - -def main(): - - set_title() - - cmd_clone.run(0) # レポジトリをクローン - - cmd_flag = True - while (cmd_flag): - print("コマンドを入力してください") - in_cmd = input(">>> ") - cmd_flag = cmd_seek.run(repo.get_repo(), in_cmd) - - set_end() - -# 最初に実行 -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/pic/sample_message.png b/pic/sample_message.png new file mode 100644 index 0000000..c5e84f1 --- /dev/null +++ b/pic/sample_message.png Binary files differ diff --git a/pic/sample_plot.png b/pic/sample_plot.png new file mode 100644 index 0000000..8991d6c --- /dev/null +++ b/pic/sample_plot.png Binary files differ diff --git a/pic/wordcloud_message_author/.gitkeep b/pic/wordcloud_message_author/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/pic/wordcloud_message_author/.gitkeep diff --git a/repo.py b/repo.py deleted file mode 100644 index b8b1760..0000000 --- a/repo.py +++ /dev/null @@ -1,19 +0,0 @@ -# repo - -import git - -# レポジトリクラス -class Repo: - def __init__(self): - self.repo = git.Repo - - def clone_repo(self, url, path): - self.repo = git.Repo.clone_from(url, path) # レポジトリをクローン - -r = Repo() # インスタンスを生成 - -def clone_repo(url, path): - r.clone_repo(url, path) - -def get_repo(): - return r.repo \ No newline at end of file diff --git a/sample_message.png b/sample_message.png deleted file mode 100644 index c5e84f1..0000000 --- a/sample_message.png +++ /dev/null Binary files differ diff --git a/sample_plot.png b/sample_plot.png deleted file mode 100644 index 8991d6c..0000000 --- a/sample_plot.png +++ /dev/null Binary files differ diff --git a/src/cmd_clone.py b/src/cmd_clone.py new file mode 100644 index 0000000..1a41fb0 --- /dev/null +++ b/src/cmd_clone.py @@ -0,0 +1,49 @@ +# clone + +import os + +import repo + +# フォルダを削除 +def rmtree(top): + for root, dirs, files in os.walk(top, topdown=False): + for name in files: + filename = os.path.join(root, name) + os.chmod(filename, 0o777) + os.remove(filename) + for name in dirs: + os.rmdir(os.path.join(root, name)) + os.rmdir(top) + +def run(first_flag): + root_path = "project" # レポジトリのパス + + print("解析するレポジトリのURLを入力してください") + url = input(">>> ") + + # 最初だけ確認 + if os.path.isdir(root_path): + if first_flag == 0: + rmtree(root_path) # projectフォルダが存在していれば削除 + + clone_flag = True + while clone_flag: + try: + # "://"でURLか判定 + if url.find("://"): + file_name = url[url.rfind('/') + 1:] # 一番後ろのファイル名を抽出 + + path = root_path + "/" + file_name # project/.. + + # 既にクローン済みの場合、pathの最後に(i)をつける + i = 1 + while os.path.isdir(path): + path = root_path + "/" + file_name + "({:d})".format(i) + i += 1 + + repo.clone_repo(url, path) # レポジトリをクローン + print("レポジトリをクローンしました\n") + clone_flag = False + except Exception as err: + print("レポジトリをクローン出来ませんでした\nもう一度、入力してください") + url = input(">>> ") \ No newline at end of file diff --git a/src/cmd_diff.py b/src/cmd_diff.py new file mode 100644 index 0000000..58c568d --- /dev/null +++ b/src/cmd_diff.py @@ -0,0 +1,46 @@ +# diff + +import sys +from tqdm import tqdm + +# 変更行から文字を検索し、その行を抜き出す +def search_lines(repo, hexsha_after, hexsha_before, commit_no): + s = repo.git.diff(hexsha_after + ".." + hexsha_before) # diffログを"s"に入れる + lines = s.splitlines() # 行ごと(改行判定(split)もして)リスト化 + + search_flag = "False" + search = [] + for line in lines: # 行ごとにまわす + if line.startswith("+") or line.startswith("-"): # もしも行の先頭が"+"or"-""の時... + # if "@" in line: # もしも"@"が含まれていた時... + search.append(line) + search_flag = "True" + + if search_flag: + print("\n--- " + str(commit_no+1) + " commit .. " + str(commit_no) + " commit ---\n") + for list in search: #ログで見やすく改行するためのfor文 + print(list) + +def run(repo): + sys.stdout = open('./log/diff.log',"w+", encoding="utf_8_sig") # 標準出力をdiff.logに変更 + + sum_commits = repo.git.rev_list('--count', 'HEAD') # コミットの総数 + commit_count = 0 + hexsha_after = "HEAD" # 差分取得用のハッシュ値(親) + + with tqdm(total=int(sum_commits), desc='diff.log') as pbar: # プログレスバーの設定 + for commit in repo.iter_commits(): + commit_no = int(sum_commits) - commit_count + + if commit_count != 0: + # print(repo.git.diff(hexsha + ".." + commit.hexsha)) # ファイルの差分を取得 + + search_lines(repo, hexsha_after, commit.hexsha, commit_no) # 変更行から文字を検索し、その行を抜き出す + + hexsha_after = commit.hexsha + commit_count += 1 + pbar.update(1) # プログレスバーの進捗率を更新 + + search_lines(repo, hexsha_after, "4b825dc642cb6eb9a060e54bf8d69288fbee4904", 0) # 最初のコミットの差分 + + sys.stdout = sys.__stdout__ # 標準出力をコンソールにもどす \ No newline at end of file diff --git a/src/cmd_help.py b/src/cmd_help.py new file mode 100644 index 0000000..0a0267d --- /dev/null +++ b/src/cmd_help.py @@ -0,0 +1,10 @@ +# help + +def run(): + print("help : コマンド一覧を表示") + print("clone: リポジトリをクローン") + print("log : ログを確認") + print("diff : ファイルの差分を確認") + print("plot : グラフを描画") + print("message:コミットメッセージを解析") + print("exit : 終了") \ No newline at end of file diff --git a/src/cmd_log.py b/src/cmd_log.py new file mode 100644 index 0000000..dafdb17 --- /dev/null +++ b/src/cmd_log.py @@ -0,0 +1,127 @@ +# log + +import csv +from tqdm import tqdm + +import contributor as con + +# コントリビュータの追加した行などを更新 +def add_con_lines(c, insertions, deletions): # c:contributors + c.add_insertions(insertions) # 追加した行 + c.add_deletions(deletions) # 削除した行 + +# コントリビュータの更新 +def set_contributor(c, author, insertions, deletions, commit): # c:contributors + # リストの重複を確認して追加 + i = 0 + for j in range(len(c)): + # authorが既に存在するか確認 + if author in c[i].get_name(): + c[i].add_commit_count(1) + add_con_lines(c[i], insertions, deletions) + c[i].set_first_commit(commit.committed_datetime.strftime('%Y-%m-%d')) + break + i += 1 + # authorがまだ登録されていない場合、追加 + if i == len(c): + c.append(con.Contributor(author, 1)) + add_con_lines(c[i], insertions, deletions) + c[i].set_last_commit(commit.committed_datetime.strftime('%Y-%m-%d')) + +def run(repo): + # log.csv + f_log = open("./log/log.csv","w+", encoding="utf_8_sig", newline='') + csv_log = csv.writer(f_log) + # csvヘッダー追加 + csv_log.writerow([ + 'commit_no', + 'author', + 'committed_datetime', + 'message', + 'hexsha']) + + # contributors.csv + f_con = open("./log/contributors.csv","w+", encoding="utf_8_sig", newline='') + csv_con = csv.writer(f_con) + csv_con.writerow([ + 'Contributor', + 'Commits(%)', + '+lines', + '-lines', + 'First commit', + 'Last commit', + 'Active days', + 'Ranking']) + + sum_commits = repo.git.rev_list('--count', 'HEAD') # コミットの総数 + commit_count = 0 + commit_files = 0 # 変更したファイル数 + sum_insertions = 0 # 追加した行数の合計 + sum_deletions = 0 # 削除した行数の合計 + lines = 0 # 変更行の合計 + merge_count = 0 # マージコミット数 + contributors = [] + with tqdm(total=int(sum_commits), desc='log.csv') as pbar: # プログレスバーの設定 + for commit in repo.iter_commits(): + commit_no = int(sum_commits) - commit_count + insertions = 0 # 追加した行数(コミットごと) + deletions = 0 # 削除した行数(コミットごと) + + file_list = commit.stats.files # ファイルごとの変更履歴(行) + for file_name in file_list: + commit_files += 1 + insertions += file_list.get(file_name).get('insertions') # 追加した行数 + deletions += file_list.get(file_name).get('deletions') # 削除した行数 + lines += file_list.get(file_name).get('lines') # 変更行の合計 + + # log.csvに書き込み + csv_log.writerow([ + commit_no, + commit.author, + commit.committed_datetime.strftime('%Y-%m-%d %H:%M:%S'), + commit.message, + commit.hexsha]) + commit_count += 1 + + # コントリビュータを更新 + set_contributor(contributors, str(commit.author), insertions, deletions, commit) + + sum_insertions += insertions + sum_deletions += deletions + + # マージコミット数を計測 + if commit.message.startswith("Merge"): + merge_count += 1 + + pbar.update(1) # プログレスバーの進捗率を更新 + + rank = 1 + with tqdm(total=len(contributors), desc='contributors.csv') as pbar: + for con in sorted(contributors, key=lambda c: c.commit_count, reverse=True): + # contributors.csvに書き込み + commit_percent = con.get_commit_count() / int(sum_commits) * 100 + csv_con.writerow([ + con.get_name(), + str(con.get_commit_count()) + "({:.1f})".format(commit_percent), + con.get_insertions(), + con.get_deletions(), + con.get_first_commit(), + con.get_last_commit(), + 0, + rank]) + rank += 1 + pbar.update(1) + + f_log.close() + f_con.close() + + print("コミット数:" + sum_commits) + print("マージコミット数:" + str(merge_count)) + print("変更したファイル数(のべ):" + str(commit_files)) + print("・追加した行数:" + str(sum_insertions)) + print("・削除した行数:" + str(sum_deletions)) + print("・変更行の和 :" + str(lines)) + print("・変更行の差 :" + str(sum_insertions - sum_deletions)) + print("コントリビュータ:" + str(len(contributors))) + for contributor in sorted(contributors, key=lambda c: c.commit_count, reverse=True): + print(contributor) \ No newline at end of file diff --git a/src/cmd_message.py b/src/cmd_message.py new file mode 100644 index 0000000..f940c8e --- /dev/null +++ b/src/cmd_message.py @@ -0,0 +1,354 @@ +import MeCab +from wordcloud import WordCloud +import collections +import csv as c +from tqdm import tqdm +import seaborn as sns +import matplotlib.pyplot as plt +import re + + +def _mecab_wakati(text): + # 形態素解析を行う(分かち書き) + wakati_tagger = MeCab.Tagger("-Owakati") # 分かち書き + parse = wakati_tagger.parse(text) + return parse + + +def _mecab(text): + # 形態素解析を行い品詞リストを返す + tagger = MeCab.Tagger() + tagger.parse("") + node = tagger.parseToNode(text) + + node_list = [] + while node: + # 例: ['吾輩', '名詞', '代名詞', '一般', '*', '*', '*', '吾輩', 'ワガハイ', 'ワガハイ'] + node_list.append([node.surface]+node.feature.split(",")) + node = node.next + node_list = node_list[1:-1] # BOS/EOSタグを除外 + + return node_list + + +# キーワード解析 +def keyword_analy(text): + key_out = [] + key_list = ["ように", "修正", "追加", "削除", "作成", "設定", "保存", + "変更", "編集", "更新", "整理", "調整", "実装", "表示", "化"] + for key in key_list: + if key in text: + key_out.append(key) + return key_out + + +class WordCloudGenerator: + """ + WordCloud + """ + out_file_name = "" + + def __init__(self, font_path, background_color, width, height, collocations, + stopwords, max_words, regexp): + """ + 出力パラメータ初期化 + """ + self.font_path = font_path + self.background_color = background_color + self.width = width + self.height = height + self.collocations = collocations + self.stopwords = stopwords + self.max_words = max_words + self.regexp = regexp + + def wordcloud_draw(self, parse): + """ + wordcloud画像を出力 + @param + parse 形態素解析結果 + """ + self.wordcloud = WordCloud(font_path=self.font_path, background_color=self.background_color, width=self.width, height=self.height, + collocations=self.collocations, stopwords=self.stopwords, max_words=self.max_words, regexp=self.regexp, repeat=False) + self.wordcloud.generate(parse) + self.wordcloud.to_file(self.out_file_name) + + def frequency_count(self, wakati_text): + """ + 単語の頻出頻度算出 + @param + wakati_text str 分かち書きテキスト + """ + words = wakati_text.split(" ") + words = [word for word in words if word not in self.stopwords] + word_freq = collections.Counter(words) + return word_freq + + def frequency_count_jp(self, wakati_text): + """ + 日本語の単語頻出頻度算出 + @param + wakati_text str 分かち書きテキスト + """ + words = wakati_text.split(" ") + compile_words = re.compile('[!"#$%&\'\\\\()*+,-./:;<=>?@[\\]^_`{|}~「」〔〕“”〈〉『』【】&*・()$#@。、?!`+¥%]') + compile_abc_123 = re.compile(r'[a-zA-Z0-90-9]') + words_jp = [] + for word in words: + if not bool(compile_words.search(word)): + if not bool(compile_abc_123.search(word)): + words_jp.append(word) + word_freq = collections.Counter(words_jp) + return word_freq + + +def _get_all_commit_message(repo): + """ + すべてのcommit messageを取得する + """ + all_commit_message = "" + with open("log/eliminate_message.txt", "w", encoding="utf-8") as f: + for commit in repo.iter_commits(): + # Mergeから始まるcommit messageは除外 + if not commit.message.startswith('Merge'): + all_commit_message += commit.message + + try: + f.write(commit.author) + except TypeError: + pass + f.write(","+commit.message+"\n") + return all_commit_message + + +def _get_commit_message_by_author(repo, author): + """ + 指定したauthorのcommit messageを取得する + """ + commit_message = "" + for commit in repo.iter_commits(): + if commit.author == author: + # Mergeから始まるcommit messageは除外 + if not commit.message.startswith('Merge'): + commit_message += commit.message + return commit_message + + +def _wordcloud_all_messages(repo, wordCloudGenerator): + """ + すべてのcommit messageでwordcloudを作成する + """ + + # 入力テキストファイル + OUT_FILE_NAME = "pic/wordcloud_message.png" + + # 形態素解析 + text = _get_all_commit_message(repo) + mecab_all = _mecab(text) # 形態素解析 + + # 名詞及び名詞連結を取得# + """ + 名詞連結は,現状うまく動かないので,一旦コメントアウト + """ + # mecab_linking_noun = [] + # for m in range(len(mecab_all)-1): + # if mecab_all[m][1] == "名詞" and mecab_all[m+1][1] == "名詞": + # mecab_linking_noun.append( + # mecab_all[m][0]+mecab_all[m+1][0]) + # elif mecab_all[m][1] == "名詞": + # mecab_linking_noun.append(mecab_all[m][0]) + # else: + # pass + + mecab_only_noun = [m[0] for m in mecab_all if m[1] == "名詞"] # 名詞のみ取得 + wakati = " ".join(mecab_only_noun) # 分かち書き + + wordCloudGenerator.out_file_name = OUT_FILE_NAME # 出力ファイル名 + wordCloudGenerator.wordcloud_draw(wakati) # 出力 + + print(f"{wordCloudGenerator.out_file_name}に画像を出力しました") + + print() + + +def _wordcloud_by_author(repo, wordCloudGenerator): + """ + authorごとにwordcloudを作成する + """ + + # 入力テキストファイル + OUT_FILE_NAME = "pic/wordcloud_message_author/{}.png" + + # すべてのauthorを取得 #この方法はちょっと時間がかかるかも.最適化の余地あり. + authors = set() + for commit in repo.iter_commits(): + authors.add(commit.author) + + # 各authorのcommit messageを取得 + authors_text = dict() + for author in authors: + # authorの名前は一緒だが,メアドが違う場合があるとき,同じauthorとみなしてmessageを結合する + if author.name in authors_text: + authors_text[author.name] += _get_commit_message_by_author( + repo, author) + else: + authors_text[author.name] = _get_commit_message_by_author( + repo, author) + + for author, text in authors_text.items(): + # 形態素解析 + mecab_all = _mecab(text) # 形態素解析 + + # リストが空の場合はスキップ + if len(mecab_all) == 0: + continue + + # 名詞及び名詞連結を取得# + """ + 名詞連結は,現状うまく動かないので,一旦コメントアウト + """ + # mecab_linking_noun = [] + # for m in range(len(mecab_all)-1): + # if mecab_all[m][1] == "名詞" and mecab_all[m+1][1] == "名詞": + # mecab_linking_noun.append( + # mecab_all[m][0]+mecab_all[m+1][0]) + # elif mecab_all[m][1] == "名詞": + # mecab_linking_noun.append(mecab_all[m][0]) + # else: + # pass + + mecab_only_noun = [m[0] for m in mecab_all if m[1] == "名詞"] # 名詞のみ取得 + wakati = " ".join(mecab_only_noun) # 分かち書き + + wordCloudGenerator.out_file_name = OUT_FILE_NAME.format(author) # 出力ファイル名 + + wordCloudGenerator.wordcloud_draw(wakati) # 出力 + + print(f"{wordCloudGenerator.out_file_name}に画像を出力しました") + + print("すべてのcontributorのwordcloudを出力しました") + print() + + +def run(repo): + # message.csv + f = open("./log/message.csv", "w+", encoding="utf_8_sig", newline='') + csv = c.writer(f) + # csvヘッダー追加 + csv.writerow([ + 'commit_no', + 'message', + 'len', + 'key_flag', + 'keyword', + 'marp_flag' + 'morpheme']) + + sum_commits = repo.git.rev_list('--count', 'HEAD') # コミットの総数 + commit_count = 0 + sum_message_len = 0 # メッセージの文字数合計 + key_match_count = 0 # キーワードの一致回数合計 + # commit message を取得 + with tqdm(total=int(sum_commits), desc='message.csv') as pbar: # プログレスバーの設定 + for commit in repo.iter_commits(): + commit_no = int(sum_commits) - commit_count + message_len = int(len(commit.message)) - 1 + sum_message_len += message_len + keyword = keyword_analy(commit.message) + key_flag = len(keyword) + if key_flag == 0: + keyword = "none" + else: + key_match_count += 1 + + # message.csvに書き込み + csv.writerow([ + commit_no, + commit.message, + message_len, + key_flag, + keyword, + 0, + "none"]) + + commit_count += 1 + + pbar.update(1) # プログレスバーの進捗率を更新 + + """ + wordcloud生成処理 + """ + #### パラメータ #### + STOP_WORDS = [" ", " "] # ストップワード + MAX_WORDS = 2000 # 出力個数の上限 + WIDTH = 500 # 出力画像の幅 + HEIGHT = 500 # 出力画像の高さ + FONT_FILE = "font/ipaexg.ttf" # フォントファイルのパス + + wordCloudGenerator = WordCloudGenerator(font_path=FONT_FILE, background_color="white", width=WIDTH, height=HEIGHT, collocations=False, + stopwords=STOP_WORDS, max_words=MAX_WORDS, regexp=r"[\w']+") # WordCloud初期化 + + _wordcloud_by_author(repo, wordCloudGenerator) # authorごとにwordcloudを作成 + # _wordcloud_all_messages(repo, wordCloudGenerator) # 全メッセージをwordcloudにして出力 + + # 単語の頻出頻度 + wordCloudGenerator.out_file_name = "./pic/word_frequency.png" + + """マージ前の処理と同じはず""" + mecab_all = _mecab(_get_all_commit_message(repo)) # 形態素解析 + mecab_only_noun = [m[0] for m in mecab_all if m[1] == "名詞"] # 名詞のみ取得 + wakati = " ".join(mecab_only_noun) # 分かち書き + + frequency_words = wordCloudGenerator.frequency_count_jp(wakati).most_common(30) + sns.set(context="talk", font='Yu Gothic') + fig = plt.subplots(figsize=(18, 8)) + sns.countplot(y=mecab_only_noun, order=[i[0] for i in frequency_words]) + plt.subplots_adjust(left=0.175, right=0.95, bottom=0.12, top=0.95) + plt.savefig("pic/frequency_words.png") + print("pic/frequency_words.pngに画像を出力しました") + + print("---メッセージ解析結果---") + print("総メッセージ数:" + sum_commits) + print("文字数の平均:{:.1f}".format(sum_message_len/int(sum_commits))) + print("キーワード一致回数:" + str(key_match_count)) + print() + + f.close() + + +if __name__ == "__main__": + OUT_FILE_NAME = "pic/wordcloud_message.png" + + TEXT = "吾輩は吾輩である.名前はスーパー吾輩である.Yes, I am wagahai." + + mecab_all = _mecab(TEXT) # 形態素解析 + + # 名詞及び名詞連結を取得# + """ + 名詞連結は,現状うまく動かないので,一旦コメントアウト + """ + # mecab_linking_noun = [] + # for m in range(len(mecab_all)-1): + # if mecab_all[m][1] == "名詞" and mecab_all[m+1][1] == "名詞": + # mecab_linking_noun.append( + # mecab_all[m][0]+mecab_all[m+1][0]) + # elif mecab_all[m][1] == "名詞": + # mecab_linking_noun.append(mecab_all[m][0]) + # else: + # pass + + mecab_only_noun = [m[0] for m in mecab_all if m[1] == "名詞"] # 名詞のみ取得 + + #### パラメータ #### + STOP_WORDS = [" "] # ストップワード + MAX_WORDS = 2000 # 出力個数の上限 + WIDTH = 500 # 出力画像の幅 + HEIGHT = 500 # 出力画像の高さ + FONT_FILE = "data/ipaexg.ttf" # フォントファイルのパス + + wakati = " ".join(mecab_only_noun) # 分かち書き + + wordCloudGenerator = WordCloudGenerator(font_path=FONT_FILE, background_color="white", width=WIDTH, height=HEIGHT, collocations=False, + stopwords=STOP_WORDS, max_words=MAX_WORDS, regexp=r"[\w']+") # WordCloud初期化 + wordCloudGenerator.out_file_name = OUT_FILE_NAME # 出力ファイル名 + wordCloudGenerator.wordcloud_draw(wakati) # 出力 diff --git a/src/cmd_plot.py b/src/cmd_plot.py new file mode 100644 index 0000000..ccc3e7b --- /dev/null +++ b/src/cmd_plot.py @@ -0,0 +1,236 @@ +# plot + +import matplotlib.pyplot as plt +import calendar +import datetime +from datetime import datetime as dt +import csv +import seaborn as sns +import pandas as pd +from tqdm import tqdm + +# 現在の年を取得 +def get_year(): + currentDateTime = datetime.datetime.now() + date = currentDateTime.date() + year = date.strftime("%Y") + return int(year) + +# 曜日を取得 +def get_dow(day): # day of week + dow = datetime.datetime.strptime(day, '%Y-%m-%d').strftime('%a') + return dow + +# 曜日を数字で取得 +def get_dow_no(dow): + if (dow == "Sun"): return 0 + elif (dow == "Mon"): return 1 + elif (dow == "Tue"): return 2 + elif (dow == "Wed"): return 3 + elif (dow == "Thu"): return 4 + elif (dow == "Fri"): return 5 + elif (dow == "Sat"): return 6 + +# 月を英語の文字列で取得 +def get_month_en(day): # day of week + month_en = datetime.datetime.strptime(day, '%Y-%m-%d').strftime('%b') + return month_en + +# 月が変わった(week+0.5)を取得 +def get_month_change_point(year_dayslist): + month_point = [] # 月が替わるタイミングのweek + + day_count = 0 + week = 0 + for month in range(12): + month_point.append(week+0.5) + for i in range(calendar.monthrange(int(get_year()), month+1)[1]): + dow = get_dow(year_dayslist[day_count]) + day_count += 1 + if dow == "Sat": + week += 1 + + return month_point + +# 現在の年の日数を取得 +def calc_days(): + year_days = 0 + for i in range(12): + year_days += calendar.monthrange(get_year(), i+1)[1] + return year_days + +# 現在の年の日付をリストで取得 +def get_year_dayslist(): + year_dayslist = [] + for month in range(12): + for day in range(calendar.monthrange(int(get_year()), month+1)[1]): + year_dayslist.append("{:<4d}-{:0>2d}-{:0>2d}".format(get_year(), month+1, day+1)) + return year_dayslist + +# 現在の年のコミットデータを作成 +def set_commit_calendar( year_days, year_dayslist, committed_year, committed_datetimes): + f = open("./log/commit_calendar.csv","w+", encoding="utf_8_sig", newline='') + csv_writer = csv.writer(f) + csv_writer.writerow([ + 'year', + 'month', + 'month_en', + 'day', + 'dow_no', + 'dow', + 'week', + 'commit']) # csvヘッダー追加 + + day_count = 0 + week = 0 + # 現在の年の日ごとコミット数を計算 + with tqdm(total=year_days, desc='commit_calendar.csv') as pbar: # プログレスバーの設定 + for month in range(12): + for day in range(calendar.monthrange(int(get_year()), month+1)[1]): + commit_count = committed_datetimes.count(year_dayslist[day_count]) + dow = get_dow(year_dayslist[day_count]) + dow_no = get_dow_no(dow) + month_en = get_month_en(year_dayslist[day_count]) + # committed_year.setdefault(year_dayslist[day_count], committed_datetimes.count(year_dayslist[day_count])) + csv_writer.writerow([ + get_year(), + month+1, + month_en, + day+1, + dow_no, + dow, + week, + commit_count]) # csvファイルに書き込み + day_count += 1 + + if dow == "Sat": + week += 1 + + pbar.update(1) # プログレスバーの進捗率を更新 + + f.close() + +# 日付差の日数を算出(リストに最終日も含めたいので、+1) +def get_dayslist(committed_datetimes, sum_commits): + dayslist = [] # 最初から最後のコミット間の日付リスト + first_commit = committed_datetimes[int(sum_commits)-1] + last_commit = committed_datetimes[0] + # 日付条件の設定 + strdt = dt.strptime(first_commit, '%Y-%m-%d').date() # 開始日 + enddt = dt.strptime(last_commit, '%Y-%m-%d').date() # 終了日 + # 日付差の日数を算出(リストに最終日も含めたいので、+1しています) + days_num = (enddt - strdt).days + 1 + + for i in range(days_num): + dayslist.append(strdt + datetime.timedelta(days=i)) # 日付差のリスト + + return dayslist + +# コミットの合計値を日付順で計算し、csvに出力 +def set_commit_transition(committed_datetimes, dayslist): + f = open("./log/commit_transition.csv","w+", encoding="utf_8_sig", newline='') + csv_writer = csv.writer(f) + csv_writer.writerow([ + 'day', + 'commit', + 'sum commit']) # csvヘッダー追加 + + day_commitlist = [] + sum_commitlist = [] + sum_commit = 0 + # 現在の年の日ごとコミット数を計算 + with tqdm(total=len(dayslist), desc='commit_transition.csv') as pbar: # プログレスバーの設定 + for day in dayslist: # コミットの合計値を日付順で計算 + day_commits = committed_datetimes.count(str(day)) + day_commitlist.append(day_commits) + sum_commit += day_commits + sum_commitlist.append(sum_commit) + + csv_writer.writerow([ + day, + day_commits, + sum_commit]) # csvファイルに書き込み + + pbar.update(1) # プログレスバーの進捗率を更新 + + f.close() + return day_commitlist, sum_commitlist + +def run(repo): + + # ------------ + # --- fig2 --- + # ------------ + + sum_commits = repo.git.rev_list('--count', 'HEAD') # コミットの総数 + # コミット履歴を取得 + committed_datetimes = [] # コミットした日付リスト + for commit in repo.iter_commits(): + committed_datetimes.append(commit.committed_datetime.strftime('%Y-%m-%d')) + + dayslist = get_dayslist(committed_datetimes, sum_commits) # 日付差の日数を算出 + day_commitlist, sum_commitlist = set_commit_transition(committed_datetimes, dayslist) # コミットの合計値を日付順で計算 + + # ------------ + # --- fig1 --- + # ------------ + + year_days = calc_days() # 現在の年の日数 + year_dayslist = get_year_dayslist() # 現在の年の日付リスト + committed_year = {} # 現在の年の日ごとコミット数 + mcp = get_month_change_point(year_dayslist) # 月が変わった(week+0.5)を取得 + + # コミットデータを作成 + set_commit_calendar(year_days, year_dayslist, committed_year, committed_datetimes) + + # ------------ + # --- plot --- + # ------------ + + # --- fig1 --- + + # CSV読み込み + df1 = pd.read_csv("./log/commit_calendar.csv",sep=",") + df1.columns = ['year','month','month_en','day','dow_no','dow', 'week', 'commit'] + df1 = df1.pivot('dow_no','week','commit') + + fig1, ax1 = plt.subplots(figsize=(10, 3)) # 10対3のプロットを作成 + + sns.heatmap( + df1, + cmap="Greens", + linewidths=.25, + square=True, + cbar=False) + + ax1.set_title(str(get_year()) + " year (" + repo.git.rev_list('--count', 'HEAD') + " commit)") + ax1.set_xlabel('') + ax1.set_ylabel('') + ax1.set_yticks([1.5, 3.5, 5.5]) + ax1.set_yticklabels(['Mon', 'Wed', 'Fri'], rotation=0) + ax1.set_xticks([mcp[0], mcp[1], mcp[2], mcp[3], mcp[4], mcp[5], mcp[6], mcp[7], mcp[8], mcp[9], mcp[10], mcp[11]]) + ax1.set_xticklabels(['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], rotation=0) + + fig1.savefig("pic/commit_calendar.png", tight_layout=True) # グラフを画像で保存 + + # --- fig2 --- + + fig2, ax2 = plt.subplots(figsize=(12, 7)) + + ax2.plot(dayslist, sum_commitlist, label="sum", linestyle="-", marker="", color="lightseagreen") + ax2.plot(dayslist, day_commitlist, label="1day", linestyle="-", marker="", color="lightcoral") + ax2.grid(b=True, which='major', color='gray', linestyle='-', linewidth=0.5, alpha=0.3) + ax2.minorticks_on() + ax2.spines['right'].set_visible(False) + ax2.spines['top'].set_visible(False) + ax2.spines['bottom'].set_visible(False) + ax2.spines['left'].set_visible(False) + ax2.set_title("commit transition") + ax2.set_xlabel('date') + ax2.xaxis.set_tick_params(rotation=10) + ax2.set_ylabel('commits') + ax2.legend() + ax2.fill_between(dayslist, 0, day_commitlist, facecolor='lightcoral', alpha=0.3) + ax2.fill_between(dayslist, day_commitlist, sum_commitlist, facecolor='lightseagreen', alpha=0.3) + + fig2.savefig("pic/commit_transition.png") \ No newline at end of file diff --git a/src/cmd_seek.py b/src/cmd_seek.py new file mode 100644 index 0000000..058f7c9 --- /dev/null +++ b/src/cmd_seek.py @@ -0,0 +1,49 @@ +# コマンド処理 + +import cmd_help +import cmd_clone +import cmd_log +import cmd_diff +import cmd_plot +import cmd_message + + +def run(repo, cmd): + # help + if (cmd == "help"): + cmd_help.run() + return True + + # clone + elif (cmd == "clone"): + cmd_clone.run(1) + return True + + # log + elif (cmd == "log"): + cmd_log.run(repo) + return True + + # diff + elif (cmd == "diff"): + cmd_diff.run(repo) + return True + + # plot + elif (cmd == "plot"): + cmd_plot.run(repo) + return True + + # message + elif(cmd == "message"): + cmd_message.run(repo) + return True + + # exit + elif (cmd == "exit()" or cmd == "exit"): + return False + + # 例外 + else: + print("そのコマンドは使用できません") + return True diff --git a/src/color.py b/src/color.py new file mode 100644 index 0000000..ba6dc40 --- /dev/null +++ b/src/color.py @@ -0,0 +1,48 @@ +# 色 + +BLACK = '\033[30m' # (文字)黒 +RED = '\033[31m' # (文字)赤 +GREEN = '\033[32m' # (文字)緑 +YELLOW = '\033[33m' # (文字)黄 +BLUE = '\033[34m' # (文字)青 +MAGENTA = '\033[35m' # (文字)マゼンタ +CYAN = '\033[36m' # (文字)シアン +WHITE = '\033[37m' # (文字)白 +COLOR_DEFAULT = '\033[39m' # 文字色をデフォルトに戻す +BOLD = '\033[1m' # 太字 +UNDERLINE = '\033[4m' # 下線 +INVISIBLE = '\033[08m' # 不可視 +REVERCE = '\033[07m' # 文字色と背景色を反転 +BG_BLACK = '\033[40m' # (背景)黒 +BG_RED = '\033[41m' # (背景)赤 +BG_GREEN = '\033[42m' # (背景)緑 +BG_YELLOW = '\033[43m' # (背景)黄 +BG_BLUE = '\033[44m' # (背景)青 +BG_MAGENTA = '\033[45m' # (背景)マゼンタ +BG_CYAN = '\033[46m' # (背景)シアン +BG_WHITE = '\033[47m' # (背景)白 +BG_DEFAULT = '\033[49m' # 背景色をデフォルトに戻す +RESET = '\033[0m' # 全てリセット + +if __name__ == "__main__": + print(f'黒:{BLACK}●ABC{RESET}') + print(f'赤:{RED}●ABC{RESET}') + print(f'緑:{GREEN}●ABC{RESET}') + print(f'黄:{YELLOW}●ABC{RESET}') + print(f'青:{BLUE}●ABC{RESET}') + print(f'マゼンタ:{MAGENTA}●ABC{RESET}') + print(f'シアン:{CYAN}●ABC{RESET}') + print(f'白:{WHITE}●ABC{RESET}') + print(f'下線:{UNDERLINE}●ABC{RESET}') + print(f'太字:{BOLD}●ABC{RESET}') + print(f'不可視:{INVISIBLE}●ABC{RESET}') + print(f'反転:{REVERCE}●ABC{RESET}') + print(f'背景黒:{BG_BLACK}●ABC{RESET}') + print(f'背景赤:{BG_RED}●ABC{RESET}') + print(f'背景緑:{BG_GREEN}●ABC{RESET}') + print(f'背景黄:{BG_YELLOW}●ABC{RESET}') + print(f'背景青:{BG_BLUE}●ABC{RESET}') + print(f'背景マゼンタ:{BG_MAGENTA}●ABC{RESET}') + print(f'背景シアン:{BG_CYAN}●ABC{RESET}') + print(f'背景白:{BG_WHITE}●ABC{RESET}') + print(f'文字赤+背景緑:{RED}{BG_GREEN}●ABC{RESET}') # 文字色と背景色を変える diff --git a/src/contributor.py b/src/contributor.py new file mode 100644 index 0000000..027213b --- /dev/null +++ b/src/contributor.py @@ -0,0 +1,87 @@ +# contributor + +# コントリビュータクラス +class Contributor: + def __init__(self, name, commit_count): + self.name = name + self.commit_count = commit_count + self.insertions = 0 # 追加した行数 + self.deletions = 0 # 削除した行数 + self.first_commit = "" # 最初のコミットの日時 + self.last_commit = "" # 最後のコミットの日時 + + # 情報のprint結果を定義 + def __repr__(self): + return "commit: {:>4d} 【 {:s} 】".format(self.commit_count, str(self.name)) + + # ----------- + # --- set --- + # ----------- + + # nameを更新 + def set_name(self, name): + self.name = name + + # commit_countを更新 + def set_commit_count(self, commit_count): + self.commit_count = commit_count + + # insertionsを更新 + def set_insertions(self, insertions): + self.insertions = insertions + + # deletionsを更新 + def set_insertions(self, deletions): + self.deletions = deletions + + # 最初のコミットの日時更新 + def set_first_commit(self, commit_day): + self.first_commit = commit_day + + # 最後のコミットの日時更新 + def set_last_commit(self, commit_day): + self.last_commit = commit_day + + # ----------- + # --- get --- + # ----------- + + # nameを取得 + def get_name(self): + return self.name + + # commit_countを取得 + def get_commit_count(self): + return self.commit_count + + # commit_countを取得 + def get_insertions(self): + return self.insertions + + # commit_countを取得 + def get_deletions(self): + return self.deletions + + # 最初のコミットの日時取得 + def get_first_commit(self): + return self.first_commit + + # 最後のコミットの日時取得 + def get_last_commit(self): + return self.last_commit + + # ----------- + # --- add --- + # ----------- + + # commit_countにnumを足す + def add_commit_count(self, num): + self.commit_count += num + + # insertionsを足す + def add_insertions(self, insertions): + self.insertions += insertions + + # deletionsを足す + def add_deletions(self, deletions): + self.deletions += deletions \ No newline at end of file diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..de55568 --- /dev/null +++ b/src/main.py @@ -0,0 +1,35 @@ +# main + +import color +import cmd_seek +import cmd_clone +import repo + +# タイトルを表示 +def set_title(): + print(f"{color.CYAN} _____ _____ _ {color.RESET}") + print(f"{color.CYAN}| _ |___ ___ ___ | |_|___ ___ {color.RESET}") + print(f"{color.CYAN}| _| _| . | . || | | | | | _| {color.RESET}") + print(f"{color.CYAN}|_|\__|___| _|___||_|_|_|_|_|_|___| for Py {color.RESET}") + print(f"{color.CYAN} |_| {color.RESET}\n") + +def set_end(): + print(f"\n{color.CYAN}end{color.RESET}\n") + +def main(): + + set_title() + + cmd_clone.run(0) # レポジトリをクローン + + cmd_flag = True + while (cmd_flag): + print("コマンドを入力してください") + in_cmd = input(">>> ") + cmd_flag = cmd_seek.run(repo.get_repo(), in_cmd) + + set_end() + +# 最初に実行 +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/repo.py b/src/repo.py new file mode 100644 index 0000000..b8b1760 --- /dev/null +++ b/src/repo.py @@ -0,0 +1,19 @@ +# repo + +import git + +# レポジトリクラス +class Repo: + def __init__(self): + self.repo = git.Repo + + def clone_repo(self, url, path): + self.repo = git.Repo.clone_from(url, path) # レポジトリをクローン + +r = Repo() # インスタンスを生成 + +def clone_repo(url, path): + r.clone_repo(url, path) + +def get_repo(): + return r.repo \ No newline at end of file