In any case, I think I managed to write something that more or less does what I needed, in case anyone else needs it. The logger will need to be changed to logging
:
#!/usr/bin/env python3
import os
import re
import argparse
import subprocess
from log_store import log_store
log=log_store.add_logger('rx_setup:bver')
#-----------------------------
class data:
package = None
file_pt = None
publish = None
regex = '\s*version\s*=\s*(?:\'|")(\d)\.(\d)\.(\d)(?:\'|")\s*,\s*'
l_pkg = list()
#-----------------------------
def get_args():
parser = argparse.ArgumentParser(description='Used to bump versions of projects')
parser.add_argument('-n', '--package' , type=str, help='Package name')
parser.add_argument('-f', '--file' , type=str, help='File with packages to bump')
parser.add_argument('-p', '--publish' , type=int, help='Will publish to pypi after bumping', default=1, choices=[0, 1])
args = parser.parse_args()
data.package = args.package
data.file_pt = args.file
data.publish = args.publish
#-----------------------------
def get_list_from_file():
if data.file_pt is None:
return []
if not os.path.isfile(data.file_pt):
log.error(f'File not found: {data.file_pt}')
raise FileNotFoundError
with open(data.file_pt) as ifile:
l_package = ifile.read().splitlines()
return l_package
#-----------------------------
def initialize():
if data.package is None and data.file_pt is None:
log.error(f'Neither package name, not config was passed')
raise
if data.package is not None:
data.l_pkg.append(data.package)
data.l_pkg += get_list_from_file()
if len(data.l_pkg) == 0:
log.error('No packages found')
raise
#-----------------------------
def run_command(cmd, options=None, shell=False):
if not isinstance(options, list):
log.error(f'Invalid options argument: {options}')
raise ValueError
log.debug('-' * 30)
log.debug(f'{cmd:<10}{str(options):<50}')
log.debug('-' * 30)
stat = subprocess.run([cmd] + options, capture_output=True, shell=shell)
return stat
#-----------------------------
def get_pkg_location(pkg):
stat = run_command('pip', ['show', pkg])
if stat.returncode != 0:
log.warning(f'Cannot find {pkg}')
return
l_line = stat.stdout.splitlines()
l_line = [ line.decode('utf-8') for line in l_line]
[loc] = [ line for line in l_line if 'Location' in line]
loc = loc.split(':')[1].replace(' ', '')
loc = os.path.dirname(loc)
return loc
#-----------------------------
def increase_version(x, y, z):
x = int(x)
y = int(y)
z = int(z)
if z < 9:
z += 1
elif y < 9:
y += 1
z = 0
else:
x += 1
y = 0
z = 0
return x, y, z
#-----------------------------
def update_ver_line(ver_line):
mtch = re.match(data.regex, ver_line)
if not mtch:
log.error(f'Not a valid version matching {data.regex}: {ver_line}')
raise
x, y, z = mtch.groups()
over = f'{x}.{y}.{z}'
x, y, z = increase_version(x, y, z)
nver = f'{x}.{y}.{z}'
log.info(f'{over:<10}{"->":<5}{nver:<10}')
ver_line= ver_line.replace(over, nver)
return ver_line
#-----------------------------
def is_version_line(line):
mtch = re.match(data.regex, line)
return mtch is not None
#-----------------------------
def update_setup(ploc):
setup_path = f'{ploc}/setup.py'
if not os.path.isfile(setup_path):
log.error(f'Cannot find setup file in: {setup_path}')
raise FileNotFoundError
with open(setup_path) as ifile:
l_line = ifile.read().splitlines()
try:
[ver_line] = [line for line in l_line if is_version_line(line)]
except:
log.error(f'Cannot find one and only one version line with {data.regex} in {setup_path}')
raise
index = l_line.index(ver_line)
ver_line = update_ver_line(ver_line)
l_line[index] = ver_line
with open(setup_path, 'w') as ofile:
for line in l_line:
ofile.write(f'{line}\n')
#-----------------------------
def publish(ploc):
if data.publish == 0:
log.warning('Not publishing')
return
this_dir = os.getcwd()
log.info(f'--> {ploc}')
os.chdir(ploc)
log.info('Publishing to pypi')
run_command('rm' , options=['-rf', 'dist', 'build', '*.egg-info'])
run_command('python', options=['setup.py', 'sdist', 'bdist_wheel'] )
run_command('twine' , options=['upload', 'dist/*'] )
log.info(f'{this_dir} <---')
os.chdir(this_dir)
#-----------------------------
def bump(pkg):
log.info(f'{"":<4}{pkg:<20}')
ploc = get_pkg_location(pkg)
if ploc is None:
return
update_setup(ploc)
publish(ploc)
#-----------------------------
def main():
get_args()
initialize()
log.info('Bumping:')
for pkg in data.l_pkg:
bump(pkg)
#-----------------------------
if __name__ == '__main__':
main()
it bumps and publishes, assuming the user has a pypi token.