This repository has been archived by the owner on Mar 12, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
indexer.py
150 lines (122 loc) · 5.44 KB
/
indexer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os.path
import json
import ctypes
import pytz
from datetime import datetime
from DictDiffer import DictDiffer as differ
from termcolor import colored
# Windows attribute for a hidden and normal file.
FILE_ATTRIBUTE_HIDDEN = 0x02
FILE_ATTRIBUTE_NORMAL = 0x80
WINDOWS_FILE_NOT_FOUND_ERRNO = 2
# s
class Indexer:
# Default name for the index. Start with dot for making it hidden on linux.
FILE_NAME = ".card_index"
# Takes as a parameter a list of cards.
def __init__(self, cardList):
# The data format of the index is just the key value of the card.
# We put True as a value but we only care if the key exist or not.
indexCards = {value['key']: True for value in cardList}
# The new index made up from the fresh data.
currentIndexMap = {}
currentIndexMap['cards'] = indexCards
# We use pytz to make our datetime in UTC time.
currentIndexMap['createdOn'] = str(datetime.now(pytz.utc))
currentIndexMap['count'] = len(cardList)
self.currentIndexMap = currentIndexMap
# We try to load a previously saved index file.
try:
print("Loading the index...")
self.savedIndex = self.loadIndex()
# We verify the index. The method will print a summary and return true if there is any change.
needReIndex = self.verifyIndex()
if needReIndex:
# Recreate a new index file.
self.createIndex()
except FileNotFoundError:
print("Index not found.")
print("Creating new index...")
# Create a new index file.
self.createIndex()
self.savedIndex = self.currentIndexMap
# Use the currentIndexMap and save it as a json encoded file.
# The file is hidden.
def createIndex(self):
filepath = os.path.join('./' + self.FILE_NAME)
# If the file already exist, this will remove the hidden attribute on Windows.
# There was a permission related bug where an hidden file couldn't be overwritten.
# No clue why the problem was happening or how to fix it, but
# removing the hidden attribute is a good workaround.
Indexer.make_hidden_file(filepath, False)
with open(filepath, "w", encoding="utf-8", newline="\n") as f:
json.dump(self.currentIndexMap, f, ensure_ascii=False, sort_keys=True, indent=2, separators=(',', ': '))
# Set the hidden attribute on the file on Windows.
Indexer.make_hidden_file(filepath)
# https://stackoverflow.com/questions/25432139/python-cross-platform-hidden-file
# The static method takes the path for a file and set the hidden attribute.
# By default the file will be made hidden. Set hidden=False to make it visible again.
@staticmethod
def make_hidden_file(file_name, hidden=True):
# For windows set file attribute.
if os.name == 'nt':
fileAttribute = FILE_ATTRIBUTE_HIDDEN
if not hidden:
fileAttribute = FILE_ATTRIBUTE_NORMAL
ret = ctypes.windll.kernel32.SetFileAttributesW(file_name, fileAttribute)
if not ret: # There was an error
if ctypes.WinError().errno == WINDOWS_FILE_NOT_FOUND_ERRNO:
pass
else:
raise ctypes.WinError() # ¯\_(ツ)_/¯
# Load a previously saved index file.
def loadIndex(self):
filepath = os.path.join('./' + self.FILE_NAME)
with open(filepath, 'r', encoding="utf-8", newline="\n") as f:
return json.load(f)
# Verify the saved index against the fresh data.
# Return true if the saved index needs to be refreshed, otherwise false.
# Will print a summary of deleted/added cards.
def verifyIndex(self):
needReIndex = False
# Object used to calculate the difference between the two dict.
# We only pass the "cards" key because it contain all the cards and we are not interested in the card
# counts or the createdOn key.
diff = differ(self.currentIndexMap['cards'], self.savedIndex['cards'])
# Set of keys that were added.
added = diff.added()
# Set of keys that were removed.
removed = diff.removed()
if len(added) > 0 or len(removed) > 0:
needReIndex = True
self.printSummary(added, removed)
return needReIndex
# Todo: prompt action if something changed.
# Todo: Write a machine friendly log that could be used to automate.
def printSummary(self, added, removed):
if not (len(added) or len(removed)):
return
message = "SUMMARY OF CHANGES"
# Print an header.
print("=".center(80, "="))
print('\n'.join('{:^80}'.format(s) for s in message.split('\n')))
print("=".center(80, "="))
if len(added) > 0:
print()
print("The following cards were added: \n")
for card in added:
print(colored(card, "green"))
print()
if len(removed) > 0:
print()
print("The following cards were removed: \n")
for card in removed:
print(colored(card, "red"))
print()
if len(removed) > 0 and len(added) > 0:
print(colored("WARNING: ", "yellow"))
print("It's possible one of the card(s) was renamed.\n")
print("=".center(80, "="))
print()