Initial commit
This commit is contained in:
parent
167f382b76
commit
2433a34364
|
@ -0,0 +1 @@
|
|||
Releases
|
|
@ -0,0 +1,3 @@
|
|||
# Auto-Firmware-Release
|
||||
|
||||
This program aims to automate some of the annoying bits of making a firmware release.
|
|
@ -0,0 +1 @@
|
|||
hello, this is another file
|
|
@ -0,0 +1 @@
|
|||
hello, this is another file
|
|
@ -0,0 +1 @@
|
|||
hello, this is a file
|
|
@ -0,0 +1,16 @@
|
|||
# v0.1.3
|
||||
|
||||
* Fix what I hope is all the bugs
|
||||
|
||||
# v0.1.2
|
||||
|
||||
* Fix another silly bug
|
||||
|
||||
# v0.1.1
|
||||
|
||||
* Fix some stupid bugs
|
||||
|
||||
# v0.1.0
|
||||
|
||||
Initial version
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# v0.2.1
|
||||
|
||||
* Fix the feature
|
||||
|
||||
# v0.2.0
|
||||
|
||||
* Implement crazy new feature
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"product_name" : "Product_Name",
|
||||
"gsd" : "999999",
|
||||
"releases_directory": "Releases",
|
||||
"changelog":"changelogs/",
|
||||
"releases" : [
|
||||
{
|
||||
"release_name": "Release",
|
||||
"description": "Release Build",
|
||||
"build_directory" : "build/release",
|
||||
"build_file_name" : "file",
|
||||
"copy_extensions" : [ "hex", "elf" ]
|
||||
},
|
||||
{
|
||||
"release_name": "Debug",
|
||||
"description": "Debugging Build",
|
||||
"build_directory" : "build/debug",
|
||||
"build_file_name" : "file",
|
||||
"copy_extensions" : [ "hex", "elf" ]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
#!/usr/bin/python3
|
||||
import logging
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
import os
|
||||
import hashlib
|
||||
from shutil import copyfile
|
||||
from datetime import datetime
|
||||
|
||||
logger = logging.getLogger()
|
||||
handler = logging.StreamHandler(stream=sys.stderr)
|
||||
formatter = logging.Formatter(
|
||||
'%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="mkrelease",
|
||||
description="Automatically package a firmware release."
|
||||
)
|
||||
|
||||
parser.add_argument('-c', '--config', dest="config_location", action="store", help="The location of the config file.", default="./release-config.json")
|
||||
parser.add_argument('version', help="Version you wish to release. Use https://semver.org")
|
||||
parser.add_argument('--verbose', help="Enable verbose logging output.", action="store_true", default=False)
|
||||
|
||||
def build_version_string(gsd_num : str, out_name:str, version_number:str, release_type:str, file_extension:str):
|
||||
return f'GSD-{gsd_num}-{out_name}-{version_number}-{release_type}.{file_extension}'
|
||||
|
||||
def md5_hash_of(file):
|
||||
with open(file, 'rb') as f:
|
||||
file_hash = hashlib.md5()
|
||||
while chunk := f.read(8192):
|
||||
file_hash.update(chunk)
|
||||
|
||||
return file_hash.hexdigest()
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.verbose:
|
||||
logger.disabled = True
|
||||
|
||||
|
||||
logger.debug("Attempting to read config file...")
|
||||
|
||||
config = None
|
||||
|
||||
try:
|
||||
config = json.load(open(args.config_location))
|
||||
except Exception as e:
|
||||
logger.error(args.config_location + ": " + str(e))
|
||||
|
||||
assert config is not None
|
||||
|
||||
logger.debug("Config file read.")
|
||||
|
||||
release_dir = f'./{config["releases_directory"]}/{args.version}/'
|
||||
|
||||
print("The following releases will be created:")
|
||||
|
||||
assert config["releases"] is not None
|
||||
|
||||
missingfiles = []
|
||||
|
||||
binaries_manifest = []
|
||||
|
||||
print(release_dir)
|
||||
for release in config["releases"]:
|
||||
for ext in release["copy_extensions"]:
|
||||
build_file_path = f'./{release["build_directory"]}/{release["build_file_name"]}.{ext}'
|
||||
output_file_path = build_version_string(config["gsd"]
|
||||
, config["product_name"]
|
||||
, args.version
|
||||
, release["release_name"]
|
||||
, ext)
|
||||
try:
|
||||
os.stat(build_file_path)
|
||||
except Exception as e:
|
||||
logging.error(f"Could not stat {build_file_path}:")
|
||||
logging.error(e)
|
||||
missingfiles.append(build_file_path)
|
||||
|
||||
print('\t'+ output_file_path + f'\t({build_file_path})')
|
||||
|
||||
binaries_manifest.append((build_file_path, release_dir + output_file_path))
|
||||
|
||||
|
||||
if len(missingfiles) > 0:
|
||||
logger.error("Exiting due to missing source files.")
|
||||
print("The following files were not able to be found:")
|
||||
[print(f"\t{path}") for path in missingfiles]
|
||||
exit(1)
|
||||
|
||||
print("\nThe following additional files will be created:")
|
||||
print(f'./{config["releases_directory"]}/{args.version}/')
|
||||
print("\trelease_notes.txt")
|
||||
|
||||
if config["changelog"] is not None:
|
||||
logger.debug("Detected changelog field. Will also create changelog.")
|
||||
if not os.path.exists(config["changelog"]):
|
||||
logger.warning("Config file does not exist.")
|
||||
print("The changelog file you provided does not exist. Check your configuration file.")
|
||||
elif os.path.isfile(config["changelog"]):
|
||||
print("\tchangelog.md (from file)")
|
||||
elif os.path.isdir(config["changelog"]):
|
||||
print("\tchangelog.md (from directory of files)")
|
||||
|
||||
print("")
|
||||
|
||||
accept_words = ["y", "yes", ""]
|
||||
deny_words = ["n", "no"]
|
||||
while True:
|
||||
print("Do you wish to proceed? [Y/n]: ", end="")
|
||||
result = input()
|
||||
|
||||
|
||||
if result.lower() in deny_words:
|
||||
print("Aborted.")
|
||||
exit(1)
|
||||
elif result.lower() not in accept_words:
|
||||
print("Don't understand what you mean.")
|
||||
else:
|
||||
print("OK, executing file operations.")
|
||||
break
|
||||
|
||||
logger.debug("Ensuring output directories exist.")
|
||||
os.makedirs(release_dir, exist_ok=True)
|
||||
|
||||
for (source,destination) in binaries_manifest:
|
||||
copyfile(source, destination)
|
||||
logger.debug(f'Copied {source} to {destination}')
|
||||
|
||||
|
||||
logger.debug(f'Generating changelog')
|
||||
|
||||
if os.path.isdir(config["changelog"]):
|
||||
with open(release_dir + "changelog.md", mode='+w') as out_log:
|
||||
for f in reversed(os.listdir(config["changelog"])):
|
||||
if os.path.isfile(f'{config["changelog"]}/{f}'):
|
||||
with open(f'{config["changelog"]}/{f}') as fi:
|
||||
for line in fi:
|
||||
out_log.write(line)
|
||||
out_log.write("\n")
|
||||
|
||||
else:
|
||||
copyfile(config["changelog"], release_dir + "/changelog.md")
|
||||
logger.debug(f'Copied {config["changelog"]} to {release_dir}/changelog.txt')
|
||||
|
||||
logger.debug("Generating release_notes.txt")
|
||||
|
||||
with open(f'{release_dir}/release_notes.txt', mode="+w") as release_notes:
|
||||
release_notes.write(f'Generated using mkrelease at {datetime.now().strftime("%Y/%m/%d %H:%M:%S")} by user {os.getlogin()}\n')
|
||||
release_notes.write("Output file manifest (name, md5 hash):\n")
|
||||
for (_, file) in binaries_manifest:
|
||||
release_notes.write(f'{file} {md5_hash_of(file)}\n')
|
Loading…
Reference in New Issue