Skip to content

Instantly share code, notes, and snippets.

@LeMeteore
Created June 18, 2019 17:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LeMeteore/cac019562822388a5d11c0ead629848c to your computer and use it in GitHub Desktop.
Save LeMeteore/cac019562822388a5d11c0ead629848c to your computer and use it in GitHub Desktop.
import re
import io
import os
import fnmatch
import argparse
import mimetypes
import subprocess
import urllib.request
from contextlib import contextmanager
@contextmanager
def cd(newdir):
""" Custom change directory command. """
prevdir = os.getcwd()
os.chdir(os.path.expanduser(newdir))
try:
yield
finally:
os.chdir(prevdir)
def get_python_files(path):
""" Retrive all Python files inside cube. """
python_files = []
with cd(path):
hg_files = subprocess.check_output(
"hg status -A", shell=True).decode().split("\n")
tracked_files = [x.split(" ", 1)[1] for x in hg_files if x.startswith("C ")]
tracked_files = filter(None, tracked_files)
for f in tracked_files:
typ = mimetypes.MimeTypes().guess_type(f)[0]
if typ == 'text/x-python':
python_files.append(f)
return python_files
def print_warning(msg):
""" Custom print coloring printed message. """
print(f'\x1b[1;33;40m {msg} \x1b[0m')
def _dtnm(path):
""" Returns a list of folders to not move. """
folders_not_to_move = []
for root, dirs, files in os.walk(path):
for d in ['bin', 'debian', 'test', '.hg', '.tox', 'cubicweb_*']:
for folder in fnmatch.filter(dirs, d):
folders_not_to_move.append(folder)
break
return folders_not_to_move
def _ftnm(path):
""" Returns a list of files to not move. """
files_not_to_move = []
for root, dirs, files in os.walk(path):
for f in ['setup.py', 'README', '*.ini', 'MANIFEST.in',
'*.txt', '*.spec', '.hgtags', '.hgrc', 'test*']:
for filename in fnmatch.filter(files, f):
files_not_to_move.append(filename)
break
return files_not_to_move
def create_cube_folder(cube_root, cube_folder):
""" Creates the cube folder. """
with cd(cube_root):
try:
if not os.path.exists(cube_folder):
os.makedirs(cube_folder)
print_warning(f'Info: {cube_folder} successfully created')
return cube_folder
else:
print_warning(f'Error: {cube_folder} already exists.')
except OSError:
print_warning(f'Error: Creating directory {cube_folder}.')
def update_pkginfo(pkginfo):
""" Update __pkginfo__.py content. """
# retrieve numversion, depends, recommends
__pkginfo__ = {}
with open(pkginfo, "r") as f:
exec(f.read(), __pkginfo__)
context = {
'numversion': __pkginfo__['numversion'],
'cubename': os.path.split(pkginfo)[0],
'distname': 'cubicweb-' + os.path.split(pkginfo)[0],
'license': __pkginfo__['license'],
'author': __pkginfo__['author'],
'author-email': __pkginfo__['author_email'],
'shortdesc': __pkginfo__['description'],
'dependencies': __pkginfo__['__depends__'],
}
if '__recommends__' in __pkginfo__:
context['__recommends__'] = __pkginfo__['__recommends__']
command = f"hg rm {pkginfo}"
subprocess.Popen(command, shell=True).wait()
url = "https://hg.logilab.org/master/cubicweb/raw-file/tip/cubicweb/skeleton/cubicweb_CUBENAME/__pkginfo__.py.tmpl"
with urllib.request.urlopen(url) as response, open(pkginfo, 'w') as out:
template = response.read().decode()
new_pkginfo = template % context
new_pkginfo = new_pkginfo.split('\n')
for l in new_pkginfo:
if "numversion" in l:
l = re.sub(r"^numversion ?= ?.*$", f"numversion = {context['numversion']}", l)
# if '>= ' in l: # not sure how to update cubicweb version to 3.24
# l = re.sub(r"'^.*cubicweb' ?: ?'>?= ?'\d{1}\.\d{1}\.\d{1}',?.*", "'cubicweb': '>= 3.24.0'", l)
out.write(l+'\n')
command = f"hg add {pkginfo}"
subprocess.Popen(command, shell=True).wait()
print_warning(f'Info: Successfully updated __pkginfo__.py.')
def move_cube_files(cube_root, cube_folder):
""" Move cube files from root to cube folder. """
ftnm = _ftnm(cube_root)
dtnm = _dtnm(cube_root)
cf = []
for root, dirs, files in os.walk(cube_root):
for filename in files:
if fnmatch.fnmatch(filename, '__pkginfo__.py'):
update_pkginfo(os.path.join(cube_root,filename))
if filename not in ftnm:
cf.append(filename)
for dirname in dirs:
if dirname not in dtnm:
cf.append(dirname)
break # we just need level 1 walk
with cd(cube_root):
for i in cf:
command = f"hg mv {i} {cube_folder}"
subprocess.Popen(command, shell=True).wait()
print_warning(f'Info: cube files successfully moved into {cube_folder}')
def replace_cube_file(cube_root, filename):
""" Delete & replace files that needs to be rewritten using the skeleton. """
with cd(cube_root):
command = f"hg rm {filename}"
subprocess.Popen(command, shell=True).wait()
url = f"https://hg.logilab.org/master/cubicweb/raw-file/tip/cubicweb/skeleton/{filename}.tmpl"
context = {'cubename': cube_root, 'distname': 'cubicweb-'+cube_root}
with urllib.request.urlopen(url) as response, open(filename, 'w') as out:
template = response.read().decode()
out.write(template % context)
command = f"hg add {filename}"
subprocess.Popen(command, shell=True).wait()
print_warning(f'Info: {filename} successfully updated')
def remove_useless_files(cube_root):
""" Remove all the files that are no more used. """
with cd(cube_root):
for filename in ['apycot.ini', 'pytestconf.py']:
command = f"hg rm {filename}"
subprocess.Popen(command, shell=True).wait()
print_warning(f'Info: {filename} successfully removed')
def fix_unittest_import(cube_root, filename):
""" Make sure we use unittest from standard lib."""
with cd(cube_root):
content = []
with open(filename, 'r') as f:
content = f.readlines()
with open(filename, 'w') as f:
for l in content:
if "unittest_main" in l:
l = re.sub(r"^from logilab\.common\.testlib import unittest_main$", r"import unittest", l)
l = re.sub(r"^ from logilab\.common\.testlib import unittest_main$", r" import unittest", l)
l = re.sub(r"^ unittest_main\(\)$", " unittest.main()", l)
f.write(l)
def fix_cube_import(cube_root, filename):
""" Make sure we import cube using new layout."""
with cd(cube_root):
content = []
with open(filename, 'r') as f:
content = f.readlines()
with open(filename, 'w') as f:
for l in content:
if "cubes." in l:
l = re.sub(r"", r"", l)
f.write(l)
def main():
parser = argparse.ArgumentParser(description='Cube mgt system.')
parser.add_argument('-p', '--path', default=".", help='cube path to migrate')
args = parser.parse_args()
path = os.path.realpath(os.path.expanduser(args.path))
cube_root = os.path.basename(path)
cube_folder = f'cubicweb_{cube_root}'
# setup.py and MANIFEST.in can just be replaced
for i in ['setup.py', 'MANIFEST.in', 'tox.ini']:
replace_cube_file(cube_root, i)
create_cube_folder(cube_root, cube_folder)
move_cube_files(cube_root, cube_folder)
py_files = get_python_files(cube_root)
# remove_useless_files
for f in py_files:
fix_unittest_import(cube_root, f)
# fix_cubes_import
# automatically call autopep8?
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment