View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0002693 | SAS.Планета | Рефакторинг / Refactoring | public | 22-04-2015 10:43 | 22-04-2015 13:31 |
| Reporter | zed | Assigned To | zed | ||
| Priority | normal | Severity | minor | Reproducibility | have not tried |
| Status | resolved | Resolution | fixed | ||
| Product Version | 141212 | ||||
| Target Version | 150915 | Fixed in Version | 150915 | ||
| Summary | 0002693: Отсортировать юниты в SASPlanet.dpr | ||||
| Description | Мне уже давно не нравится тот хаос, что творится в uses в dpr файле (особенно, необходимость лазить туда руками, после добавления нового юнита). Хочу отсортировать юниты по имени и поддерживать сортировку в автоматическом режиме. Для этого написал скриптик на питоне (в аттаче). Возможные варианты сортировки: по имени юнита или по его пути. Мне больше нравится сортировка по имени. По пути, юниты сортируются в dproj самой делфи. Сортировка не затрагивает системные юниты и юнит SASPlanet.modules. | ||||
| Additional Information | Помимо сортировки, скрипт помогает при перемещениях юнитов по папкам в файловой системе. Использование весьма простое: файловым менеджером перемещаем юниты как хотим (главное не переименовывать юнит), запускаем скрипт и получаем валидные пути к юниту в файлах проекта (dpr и dproj). Данный скрипт хочу положить в папку Tools. | ||||
| Tags | No tags attached. | ||||
| Attached Files | UnitsSortHelper.py (4,605 bytes)
#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import re
import logging
def init_log(log_file, level=logging.NOTSET):
logging.basicConfig(level=level,
format='%(asctime)s.%(msecs).03d %(levelname)-8s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
filename=log_file,
filemode='w')
console = logging.StreamHandler()
console.setLevel(level)
formatter = logging.Formatter('%(levelname)-8s %(message)s')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)
def check_path(path):
if path:
path = os.path.abspath(path)
if path and path[-1:] != os.path.sep:
path += os.path.sep
return path
def sort_dpr(proj_file, by_unit_name=True):
logging.info('Sorting uses in dpr: ' + proj_file)
def sort_func_by_unit_path(x, y):
x1 = x.split(' in ')
y1 = y.split(' in ')
return cmp(x1[1], y1[1])
def uses_to_text(uses_list, text):
for unit in uses_list:
if unit:
if text:
text += ','
text += unit
return text
with open(proj_file, 'rb') as f:
data = f.read()
uses_sys = []
uses_sorted = []
uses_text = ''
match = re.findall(r'uses\r\n(.*?);', data, re.DOTALL | re.IGNORECASE)
if match:
uses = match[0].split(',')
for pas in uses:
if ' in ' in pas.lower() and not ('sasplanet.modules' in pas.lower()):
uses_sorted.append(pas)
else:
uses_sys.append(pas)
if uses_sorted:
if by_unit_name:
uses_sorted.sort()
else:
uses_sorted.sort(cmp=sort_func_by_unit_path)
uses_text = uses_to_text(uses_sys, uses_text)
uses_text = uses_to_text(uses_sorted, uses_text)
if uses_text:
if match[0] != uses_text:
data = data.replace(match[0], uses_text)
with open(proj_file, 'wb') as f:
f.write(data)
logging.info('Sorting update')
else:
logging.info('Sorting OK')
def patch_proj_file(proj_file, proj_info):
logging.info('Patching file: ' + proj_file)
is_patched = False
# read proj
with open(proj_file, 'rb') as f:
data = f.read()
# apply patch
unit_expr = r"[\"'](.*?)[\"']"
for match in re.finditer(unit_expr, data, re.DOTALL | re.IGNORECASE):
if match.group(1).endswith('.pas'):
unit_path, unit_name = os.path.split(match.group(1))
for pas, unit in proj_info:
if unit_name in pas:
if unit != match.group(1):
is_patched = True
data = data.replace(match.group(1), unit)
logging.debug('Replaced: {} --> {}'.format(match.group(1), unit))
else:
logging.debug('OK: {} == {}'.format(match.group(1), unit))
if not is_patched:
logging.info('Proj file ' + proj_file + ' is OK')
else:
# save proj
with open(proj_file, 'wb') as f:
f.write(data)
logging.info('Proj file ' + proj_file + ' is updated')
def main(src_path):
flst = []
logging.info('Scan file system: ' + src_path)
for root, dirs, files in os.walk(src_path):
if '.bin' in dirs:
dirs.remove('.bin')
if '.dcu' in dirs:
dirs.remove('.dcu')
if '.hg' in dirs:
dirs.remove('.hg')
if '__history' in dirs:
dirs.remove('__history')
for pasfile in files:
if pasfile.endswith('.pas'):
unit = root.replace(src_path, '')
if unit:
unit += '\\'
unit += pasfile
flst.append((pasfile, unit))
logging.debug('Found ' + pasfile + ' in ' + unit)
if flst:
patch_proj_file(src_path + 'SASPlanet.dpr', flst)
patch_proj_file(src_path + 'SASPlanet.dproj', flst)
patch_proj_file(src_path + 'SASPlanet.XE2.dproj', flst)
sort_dpr(src_path + 'SASPlanet.dpr')
if __name__ == '__main__':
init_log('UnitsSortHelper.log')
src = '..\\'
main(check_path(src)) | ||||
|
|
У кого какие мысли, возражения? |
|
|
>или по его пути Так представляется логичным вот почему: поскольку файлы раскиданы по папкам, то изменения с большей вероятностью затронут меньшее количество строк в dpr. А вообще конечно не принципиально. Но вообще если решите так формировать dpr и dproj - тоже перейду на этот скрипт, только вот дополнительные файлы куда-то деть надо будет (в отдельный модуль видимо). >главное не переименовывать юнит А что страшного будет, если юнит переименуется? Старый пропадёт, новый появится. Diff-ы видно же. Чай не 100500+ файлов меняется за раз. |
|
|
Я за сортировку по пути. А еще лучше было бы сначала сортировать по префиксу в имени юнита, а потом уже по пути. Причем префиксы отсортировать не по алафавиту, а по предварительно заданному порядку: t_*.pas, c_*.pas, i_*.pas, u_*.pas, fr_*.pas, frm_*.pas |
|
|
>i_*.pas, u_*.pas Хм. А чем плохо, если будет так: i_BinaryData in 'Src\Basic\i_BinaryData.pas', u_BinaryData in 'Src\Basic\u_BinaryData.pas', u_BinaryDataByFileMapping in 'Src\Basic\u_BinaryDataByFileMapping.pas', u_BinaryDataByMemStream in 'Src\Basic\u_BinaryDataByMemStream.pas', i_BinaryDataListChangeable in 'Src\Basic\i_BinaryDataListChangeable.pas', i_BinaryDataListStatic in 'Src\Basic\i_BinaryDataListStatic.pas', u_BinaryDataListStatic in 'Src\Basic\u_BinaryDataListStatic.pas', То есть, u_ цепляем к существующему i_, если такового нет, то смотрим какой максимальный есть (CamelCase тут рулит) и цепляем туда, сортируя среди всех его u_? Не вижу смысла разделять "одноимённые" i_ и u_ пропастью в половину файлов проекта. |
|
|
>А что страшного будет, если юнит переименуется? Скрипт его проигнорирует и не исправит файлы проекта. >А еще лучше было бы сначала сортировать по префиксу в имени юнита По-моему, фигня получится. |
|
|
>проигнорирует и не исправит Упс. А я понял, что скрипт просто строит часть файла проекта заново по фактическим файлам в каталогах, просто берёт начало и конец файла, а середину с файлами и путями с нуля собирает. >фигня получится Никогда не понимал, зачем все формы так яростно совать в самый конец проекта. Так что уж лучше при сортировке вообще игнорировать префикс, чем такая вот фигня с перечнем префиксов. XE2 вполне корректно обрабатывает ситуацию внешнего изменения фалов проекта (в том же блокноте), так что после запуска скрипта среда вполне в состоянии будет сама поднять его с диска, и лазить руками в файлы проекта не понадобится, соответственно, какой там порядок, важно только для самого порядка и изменений, а не для правки руками. И где будут frm - сугубо пофигу. |
|
|
>Хм. А чем плохо, если будет так >То есть, u_ цепляем к существующему i_, если такового нет, то смотрим какой максимальный есть (CamelCase тут рулит) и цепляем туда, сортируя среди всех его u_? Нетривиальная сортировалка выходит. >>фигня получится >Никогда не понимал, зачем все формы так яростно совать в самый конец проекта. Может быть и фигня. |
|
|
Отсортировал по пути и залил в репо. Для запуска скрипта нужен python 2.7. |
|
|
>Нетривиальная сортировалка Ну в общем-то да, не сильно тривиальная. Но это проблема скрипта и принципиального наличия консенсуса в том, что это вообще НАДО. А то если например кто-либо будет руками править dpr, то толку будет мало. Поскольку мне тоже кажется предпочтительнее по папкам раскидывать, алгоритм вижу примерно такой: а) скрипт берёт файл проекта, ищет начало списка модулей и его конец (весьма тривиально по характерным строчкам в файле проекта, что для dpr что для dproj); б) проходит по дереву каталогов, строит его и в алфавитном порядке для каждой папки выполняет следующие шаги; в) получает исходный список файлов; г) сортирует i_ в чистый результирующий список (из исходного на каждом шаге обработанное удаляется); д) добавляет в этот список все u_ (по алгоритму выше, это как раз самое нетривиальное); е) добавляет в этот список все прочие файлы, для которых есть в точности одноимённый i_ или u_, непосредственно ПЕРЕД ним или любым другим с другим префиксом и той же смысловой частью имени файла (чтобы t_ и c_ соответствующие i_ были перед ними, но реализацию в u_ от i_ не отделяли) *); ж) остальное сортируется между собой тупо по алфавиту (для форм и фреймов оставляется одна соответствующая запись вместо двух имён файлов в dpr) и помешается в результирующий список в начало (для простоты, а также если будут ещё новые префиксы); з) результирующий список обрабатывается и падает в файл проекта; и) цикл повторяется, покуда не прошли все каталоги; *) если на шаге е) в список попадают одноимённые формы и фреймы, значит разработчик сделал это неспроста, и их тоже надо обработать на этом шаге аналогичным образом. Поскольку краеугольным камнем проекта является именно интерфейсный файл i_, а реализация его в u_, подобный алгоритм представляется весьма оправданным. А поскольку бардак в dpr существенно разросся с увеличением папок в проекте, делать всё равно что-то придётся. Например, я просто руками с разделяющими комментариями раскидал всё по папкам. Но идея со скриптом мне нравится больше. Особенно если его напишет уважаемый товарищ zed ))) Осталась самая "мелочь" - прийти к консенсусу. |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 22-04-2015 10:43 | zed | New Issue | |
| 22-04-2015 10:43 | zed | File Added: SASPlanet.by_unit.dpr | |
| 22-04-2015 10:44 | zed | File Added: SASPlanet.by_path.dpr | |
| 22-04-2015 10:44 | zed | File Added: UnitsSortHelper.py | |
| 22-04-2015 10:44 | zed | Note Added: 0015660 | |
| 22-04-2015 10:53 | vasketsov | Note Added: 0015663 | |
| 22-04-2015 10:53 | vdemidov | Note Added: 0015664 | |
| 22-04-2015 11:13 | vasketsov | Note Added: 0015669 | |
| 22-04-2015 11:13 | vasketsov | Note Edited: 0015669 | |
| 22-04-2015 11:21 | zed | Note Added: 0015670 | |
| 22-04-2015 11:24 | vasketsov | Note Added: 0015671 | |
| 22-04-2015 11:29 | vasketsov | Note Edited: 0015671 | |
| 22-04-2015 12:55 | vdemidov | Note Added: 0015672 | |
| 22-04-2015 13:19 | zed | Note Added: 0015673 | |
| 22-04-2015 13:19 | zed | Status | new => resolved |
| 22-04-2015 13:19 | zed | Fixed in Version | => 150915 |
| 22-04-2015 13:19 | zed | Resolution | open => fixed |
| 22-04-2015 13:19 | zed | Assigned To | => zed |
| 22-04-2015 13:20 | zed | File Deleted: SASPlanet.by_path.dpr | |
| 22-04-2015 13:20 | zed | File Deleted: SASPlanet.by_unit.dpr | |
| 22-04-2015 13:31 | vasketsov | Note Added: 0015674 | |
| 08-08-2025 13:25 | zed | Category | Рефакторинг => Рефакторинг / Refactoring |