-
Notifications
You must be signed in to change notification settings - Fork 63
/
file_expander.py
141 lines (100 loc) · 4.66 KB
/
file_expander.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
"""File Expansion of Nested screeps Source Code.
This package provides file expansion operations that targets screeps code
written in Python in order to allow files to be organized in a nested directory
structure.
Every time Transcrypt is run, user generated .py source code will be copied so
that they all sit directly under __py_build__. Only new/updated files will
actually be copied; unmodified files are not replaced in __py_build__. Files can
reside directly under src/, or in subdirectories under src/.
The -xpath option available through Transcrypt already provides this
functionality; this package serves as a replacement for anyone experiencing
problems with Transcrypt recognizing python modules stored in sub-folders, or
for those looking for an alternative to -xpath itself."""
import pathlib
import shutil
import filecmp
class FileExpander:
"""Class for managing file expansion operations.
:type base_dir: pathlib.Path
:type build_dir: pathlib.Path
"""
def __init__(self, base_dir):
"""
:param base_dir: absolute path of the screeps-starter-python directory
:type base_dir: str
"""
self.base_dir = pathlib.Path(base_dir).joinpath('src')
self.build_dir = self.verify_build_directory()
def verify_build_directory(self):
"""Verifies existence and contents of __py_build__ directory.
Missing directories are either created, or copied from its counterpart
in src/""
:return: concrete Path object of the __py_build__ directory
:rtype: pathlib.Path
"""
build_directory = self.base_dir.joinpath('__py_build__')
defs_source_directory = self.base_dir.joinpath('defs')
defs_build_directory = build_directory.joinpath('defs')
defs_source_path = str(defs_source_directory.absolute())
defs_build_path = str(defs_build_directory.absolute())
if not build_directory.is_dir():
build_directory.mkdir(exist_ok=True)
if not defs_build_directory.is_dir():
shutil.copytree(defs_source_path, defs_build_path)
self.verify_defs_integrity(defs_source_directory, build_directory)
return build_directory
@staticmethod
def verify_defs_integrity(source_dir, build_dir):
"""Verifies integrity of defs/ folder in __py_build__
File contents under src/defs are compared against __py_build__/defs; a
file update will only be triggered by modifications to files under
src/defs.
:rtype: None
"""
defs_source_files = [f.absolute() for f in source_dir.glob('**/*.py')]
for file in defs_source_files:
slice_index = file.parts.index('src') + 1
partner = build_dir.joinpath(*file.parts[slice_index:])
if not partner.is_file() or not filecmp.cmp(str(file), str(partner)):
shutil.copy2(str(file), str(partner))
def expand_files(self):
"""Creates a flattened file structure of all user-defined screeps code
Copies all modified or new .py files found directly under src/, or in
subdirectories under src/, to __py_build__.
:return: total number of files copied to __py_build__
:rtype: int
"""
target_files = self.find_target_file_paths()
copied_files = 0
for target in target_files:
partner = self.build_dir.joinpath(target.name)
target_path, partner_path = str(target.absolute()), str(partner.absolute())
if not (partner.is_file() and filecmp.cmp(target_path, partner_path)):
shutil.copy2(target_path, partner_path)
copied_files += 1
return copied_files
def find_target_file_paths(self):
"""Finds all potential target files for the file expansion operation
:return: All files to be checked by self.expand_files
:rtype: list[pathlib.Path]
"""
exclusions = [
'__pycache__',
'__javascript__',
'__py_build__',
'.idea',
'.git',
'defs'
]
target_files, target_directories = [], []
for file_object in self.base_dir.iterdir():
if not any(entry in file_object.name for entry in exclusions):
if file_object.is_file():
target_files.append(file_object)
else:
target_directories.append(file_object)
# Directories processed separately to avoid performing glob on all of src/
for directory in target_directories:
for file in directory.glob('**/*.py'):
target_files.append(file)
return target_files