mirror of https://github.com/archzfs/archzfs
parent
a960910379
commit
595d3c815c
@ -0,0 +1,379 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
# encoding: utf-8 |
||||||
|
|
||||||
|
import argparse |
||||||
|
import subprocess |
||||||
|
import os |
||||||
|
import re |
||||||
|
import logging |
||||||
|
import datetime |
||||||
|
import sys |
||||||
|
import glob |
||||||
|
|
||||||
|
SIGNING_KEY = '0EE7A126' |
||||||
|
|
||||||
|
# Prefix for logging output |
||||||
|
PREFIX = '[>>>]' |
||||||
|
|
||||||
|
from logging import Formatter, getLogger, StreamHandler, DEBUG |
||||||
|
|
||||||
|
# This function uses ansi escape sequences. |
||||||
|
# http://bluesock.org/~willg/dev/ansi.html#sequences |
||||||
|
# http://en.wikipedia.org/wiki/ANSI_escape_code |
||||||
|
# http://docs.python.org/reference/lexical_analysis.html |
||||||
|
|
||||||
|
# `\033[` is the escape sequence character. `\033` is octal. |
||||||
|
ATTR_CODES = { |
||||||
|
'bold': '1', |
||||||
|
'italic': '3', |
||||||
|
'strike': '9', |
||||||
|
'underline': '4', |
||||||
|
'erase': '\033[K', # Clear to the end of the line |
||||||
|
'reset': '\033[0m', # All attributes off |
||||||
|
} |
||||||
|
|
||||||
|
FG_COLOR_CODES = { |
||||||
|
'black': 30, |
||||||
|
'red': 31, |
||||||
|
'green': 32, |
||||||
|
'yellow': 33, |
||||||
|
'blue': 34, |
||||||
|
'magenta': 35, |
||||||
|
'cyan': 36, |
||||||
|
'white': 37, |
||||||
|
'default': 38, |
||||||
|
} |
||||||
|
|
||||||
|
BG_COLOR_CODES = { |
||||||
|
'bgred': 41, |
||||||
|
'bgblack': 40, |
||||||
|
'bggreen': 42, |
||||||
|
'bgyellow': 43, |
||||||
|
'bgblue': 44, |
||||||
|
'bgmagenta': 45, |
||||||
|
'bgcyan': 46, |
||||||
|
'bgwhite': 47, |
||||||
|
'bgdefault': 49, |
||||||
|
'bggrey': 100, |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
def ansi_builder(text, fgcolor, bgcolor, attr): |
||||||
|
"""Wrap text in an ansi escape sequence, with bolding. |
||||||
|
|
||||||
|
:color: The color to wrap the text in. |
||||||
|
:text: The text to wrap. |
||||||
|
:attr: The attribute to wrap the text in. |
||||||
|
|
||||||
|
""" |
||||||
|
fgcc = '' |
||||||
|
if fgcolor: |
||||||
|
assert(fgcolor in FG_COLOR_CODES) |
||||||
|
fgcc = str(FG_COLOR_CODES[fgcolor]) + ';' |
||||||
|
|
||||||
|
bgcc = '' |
||||||
|
if bgcolor: |
||||||
|
assert(bgcolor in BG_COLOR_CODES) |
||||||
|
bgcc = str(BG_COLOR_CODES[bgcolor]) + ';' |
||||||
|
|
||||||
|
attrc = '' |
||||||
|
if attr: |
||||||
|
assert(attr in ATTR_CODES) |
||||||
|
attrc = ATTR_CODES[attr] + ';' |
||||||
|
|
||||||
|
ccds = attrc + fgcc + bgcc |
||||||
|
# print('033[{}m{}{}'.format(ccds[:-1], text, ATTR_CODES['reset'][1:])) |
||||||
|
|
||||||
|
return '\033[{}m{}{}'.format(ccds[:-1], text, ATTR_CODES['reset']) |
||||||
|
|
||||||
|
|
||||||
|
OUTPUT_PREFIX = ansi_builder(PREFIX, 'cyan', '', 'bold') + ': ' |
||||||
|
|
||||||
|
|
||||||
|
class _ANSIFormatter(Formatter): |
||||||
|
"""Convert a `logging.LogReport' object into colored text, using ANSI |
||||||
|
escape sequences. |
||||||
|
|
||||||
|
""" |
||||||
|
def format(self, record): |
||||||
|
mtype = '' |
||||||
|
if record.levelname is 'INFO': |
||||||
|
mtype = ansi_builder(record.levelname + ' ', 'cyan', '', 'bold') |
||||||
|
elif record.levelname is 'WARNING': |
||||||
|
mtype = ansi_builder(record.levelname, 'yellow', '', 'bold') |
||||||
|
elif record.levelname is 'ERROR': |
||||||
|
mtype = ansi_builder(record.levelname, 'red', '', 'bold') |
||||||
|
elif record.levelname is 'CRITICAL': |
||||||
|
mtype = ansi_builder(record.levelname, '', 'bgred', 'bold') |
||||||
|
elif record.levelname is 'DEBUG': |
||||||
|
mtype = ansi_builder(record.levelname, '', 'bggrey', 'bold') |
||||||
|
else: |
||||||
|
mtype = ansi_builder(record.levelname, 'white', '', 'bold') |
||||||
|
tdate = get_time_string() |
||||||
|
return OUTPUT_PREFIX + mtype + ': ' + tdate + ': ' + record.msg |
||||||
|
|
||||||
|
|
||||||
|
def init_logging(level, logger=getLogger(), handler=StreamHandler()): |
||||||
|
logger = logging.getLogger() |
||||||
|
fmt = _ANSIFormatter() |
||||||
|
handler.setFormatter(fmt) |
||||||
|
logger.addHandler(handler) |
||||||
|
if not level: |
||||||
|
level = logging.WARN |
||||||
|
logger.setLevel(level) |
||||||
|
|
||||||
|
|
||||||
|
init_logging(level=DEBUG) |
||||||
|
logger = logging.getLogger(__name__) |
||||||
|
|
||||||
|
|
||||||
|
def get_time_string(): |
||||||
|
"""Returns a formatted time string. |
||||||
|
|
||||||
|
""" |
||||||
|
now = datetime.datetime.now() |
||||||
|
return now.strftime('%a %b %d %H:%M:%S %Y') |
||||||
|
|
||||||
|
|
||||||
|
def _logger(text, text_attr='', note='', note_attr='', note_fgcolor='', |
||||||
|
note_bgcolor='', date=True, prefix=True): |
||||||
|
"""Prints to stdout. |
||||||
|
|
||||||
|
_logger is responsible for making pretty output and is used throughout the |
||||||
|
entire program. Any whitepsace characters at the start or ends of the line |
||||||
|
are preserved. So lines containing '\r' will overlap. This is useful for |
||||||
|
progress bars and such. |
||||||
|
|
||||||
|
:text: The text to output. |
||||||
|
:text_attr: ANSI attribute to wrap text with. |
||||||
|
:note: String to append to the text. |
||||||
|
:note_attr: ANSI attribute to wrap note with. |
||||||
|
:note_fgcolor: Color of the appended note. |
||||||
|
:note_bgcolor: Background color of the note. |
||||||
|
:date: If true, the date will be appended. |
||||||
|
:prefix: If true, the date and OUTPUT_PREFIX will be displayed. |
||||||
|
|
||||||
|
""" |
||||||
|
prefix = OUTPUT_PREFIX |
||||||
|
if date: |
||||||
|
prefix = prefix + get_time_string() + ': ' |
||||||
|
if note: |
||||||
|
note = ansi_builder(note, note_fgcolor, note_bgcolor, note_attr) + ' ' |
||||||
|
pad_re = re.match(r'(\s*).*(\s*)', text) |
||||||
|
if pad_re: |
||||||
|
pre_pad = pad_re.group(1) |
||||||
|
pos_pad = pad_re.group(2) |
||||||
|
end = '\r' if text[-1] == '\r' else '\n' |
||||||
|
stext = text.strip() |
||||||
|
if text_attr: |
||||||
|
stext = ansi_builder(stext, '', '', text_attr) |
||||||
|
output = ''.join((pre_pad, prefix, note, stext, pos_pad, |
||||||
|
ATTR_CODES['reset'], end)) |
||||||
|
sys.stdout.write(output) |
||||||
|
|
||||||
|
|
||||||
|
def log_begin(text): |
||||||
|
"""Logs output with [Begin] appended to the start of the string. |
||||||
|
|
||||||
|
:text: The message to write to stdout. |
||||||
|
|
||||||
|
""" |
||||||
|
_logger(text, '', '[Begin]', 'bold', 'white', 'bgcyan') |
||||||
|
|
||||||
|
|
||||||
|
def log_done(text): |
||||||
|
"""Logs output with [Done] appended to the start of the string. |
||||||
|
|
||||||
|
:text: The message to write to stdout. |
||||||
|
|
||||||
|
""" |
||||||
|
_logger(text, '', '[FINISHED]', 'bold', 'white', 'bgcyan') |
||||||
|
|
||||||
|
|
||||||
|
def log_noprefix(text): |
||||||
|
"""Logs output without the prefix. |
||||||
|
|
||||||
|
:text: The message to write to stdout. |
||||||
|
|
||||||
|
""" |
||||||
|
_logger(text, date=False, prefix=False) |
||||||
|
|
||||||
|
|
||||||
|
def log_note(text, note, fgcolor, bgcolor): |
||||||
|
"""Logs output without the prefix. |
||||||
|
|
||||||
|
:text: The message to write to stdout. |
||||||
|
|
||||||
|
""" |
||||||
|
assert(fgcolor in FG_COLOR_CODES) |
||||||
|
assert(bgcolor in BG_COLOR_CODES) |
||||||
|
_logger(text, '', note, 'bold', fgcolor, bgcolor) |
||||||
|
|
||||||
|
|
||||||
|
def log(text): |
||||||
|
"""Prints to stdout with timestap and OUTPUT_PREFIX. |
||||||
|
|
||||||
|
:text: The message to write to stdout. |
||||||
|
|
||||||
|
""" |
||||||
|
_logger(text, date=True, prefix=True) |
||||||
|
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='Magically add packages to a ' |
||||||
|
'repository.') |
||||||
|
|
||||||
|
parser.add_argument('-r', nargs='?', required=True, |
||||||
|
help='Chroot path.') |
||||||
|
|
||||||
|
parser.add_argument('-l', nargs='?', required=True, |
||||||
|
help='Chroot version.') |
||||||
|
|
||||||
|
parser.add_argument('-c', action='store_true', default=False, |
||||||
|
help='Clean the chroot before building or installing.') |
||||||
|
|
||||||
|
parser.add_argument('-I', nargs='+', |
||||||
|
help='A list of packages to install into the chroot' |
||||||
|
'environment before building.') |
||||||
|
|
||||||
|
parser.add_argument('packages', nargs='+', |
||||||
|
help='A list of packages to build. For all packages, use ' |
||||||
|
'"all"') |
||||||
|
|
||||||
|
args = parser.parse_args() |
||||||
|
|
||||||
|
|
||||||
|
def set_new_sums(): |
||||||
|
"""Get new sums and change in the PKGBUILD |
||||||
|
|
||||||
|
""" |
||||||
|
for pkg in ['spl-utils', 'spl', 'zfs-utils', 'zfs']: |
||||||
|
os.chdir('devsrc/' + pkg) |
||||||
|
proc = subprocess.Popen(['makepkg', '-g'], stdout=subprocess.PIPE, |
||||||
|
stderr=subprocess.PIPE) |
||||||
|
sout, serr = proc.communicate() |
||||||
|
smsum = re.findall(r'\ *(?:sha|md)\d+sums=\([\w\s\n\']+\)', |
||||||
|
sout.decode('UTF-8')) |
||||||
|
if len(smsum) > 1: |
||||||
|
logger.warning('RE pattern returned more than one occurrence!') |
||||||
|
|
||||||
|
with open('PKGBUILD', 'r') as p_file: |
||||||
|
pkg_conf = p_file.read() |
||||||
|
|
||||||
|
pfsum = re.findall(r'\ *(?:sha|md)\d+sums=\([\w\s\n\']+\)', pkg_conf) |
||||||
|
if pfsum and pfsum[0] != smsum[0]: |
||||||
|
log_noprefix('Generating hashes for "' + pkg + '"') |
||||||
|
new_pconf = pkg_conf.replace(pfsum[0], smsum[0]) |
||||||
|
log_noprefix('Writing updated PKGBULID') |
||||||
|
with open('PKGBUILD', 'w') as p_file: |
||||||
|
p_file.write(new_pconf) |
||||||
|
else: |
||||||
|
log_noprefix('Hashes up-to-date for "' + pkg + '"') |
||||||
|
|
||||||
|
os.chdir('../../') |
||||||
|
|
||||||
|
|
||||||
|
def clean_chroot(): |
||||||
|
"""Creates a clean chroot. |
||||||
|
|
||||||
|
""" |
||||||
|
copydir = args.r + '/' + args.l |
||||||
|
if args.c: |
||||||
|
proc = subprocess.call(['sudo', 'mkdir', '-p', copydir]) |
||||||
|
if proc > 0: |
||||||
|
logger.warning('Could not create chroot diretory "' + copydir + |
||||||
|
'"') |
||||||
|
log_noprefix('Creating clean chroot at "' + copydir + '"') |
||||||
|
proc = subprocess.call(['sudo', 'rsync', '-a', '--delete', '-q', '-W', |
||||||
|
'-x', args.r + '/root/', copydir]) |
||||||
|
if proc > 0: |
||||||
|
logger.warning('A problem occurred creating the clean chroot!') |
||||||
|
|
||||||
|
|
||||||
|
def install_packages(): |
||||||
|
"""Installs the packages passed as arguments into the chroot. |
||||||
|
|
||||||
|
""" |
||||||
|
copydir = args.r + '/' + args.l |
||||||
|
for pkg in args.I: |
||||||
|
log_noprefix('Copying "' + pkg + '" to the chroot') |
||||||
|
proc = subprocess.call(['sudo', 'cp', pkg, copydir + '/' + |
||||||
|
os.path.basename(pkg)]) |
||||||
|
pac_cmd = 'pacman -U /{} --noconfirm'.format(os.path.basename(pkg)) |
||||||
|
cmd = ['sudo', '/usr/sbin/mkarchroot', '-r', pac_cmd, copydir] |
||||||
|
log_noprefix('Installing "' + pkg + '"') |
||||||
|
proc = subprocess.call(cmd) |
||||||
|
if proc > 0: |
||||||
|
logger.warning('There was a problem installing the package!') |
||||||
|
proc = subprocess.call(['sudo', 'rm', copydir + '/' + |
||||||
|
os.path.basename(pkg)]) |
||||||
|
if proc > 0: |
||||||
|
logger.warning('There was a problem removing the package!') |
||||||
|
|
||||||
|
|
||||||
|
def move_sources(): |
||||||
|
"""Move the sources to a temporary directory. |
||||||
|
|
||||||
|
""" |
||||||
|
pass |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
log_note('Welcome!', 'package.py', 'white', 'bgred') |
||||||
|
set_new_sums() |
||||||
|
|
||||||
|
if args.c: |
||||||
|
clean_chroot() |
||||||
|
|
||||||
|
if args.I: |
||||||
|
install_packages() |
||||||
|
|
||||||
|
# # for arch in ('i686', 'x86_64'): |
||||||
|
for pkg in ('spl-utils', 'spl', 'zfs-utils', 'zfs'): |
||||||
|
os.chdir('devsrc/' + pkg) |
||||||
|
proc = subprocess.call(['sudo', 'makechrootpkg', '-r', args.r, |
||||||
|
'-l', args.l, '--', '-i']) |
||||||
|
if proc > 0: |
||||||
|
logger.warning('There was a problem building "' + pkg + '"') |
||||||
|
bpkg = glob.glob('*.pkg.tar.xz') |
||||||
|
if bpkg: |
||||||
|
bpkg = bpkg[0] |
||||||
|
else: |
||||||
|
bpkg = '' |
||||||
|
proc = subprocess.call(['gpg', '--detach-sign', '-u', '0EE7A126', |
||||||
|
'--use-agent', bpkg]) |
||||||
|
if proc > 0: |
||||||
|
logger.warning('There was a problem signing "' + pkg + '"') |
||||||
|
proc = subprocess.call(['makepkg', '-S', '-f']) |
||||||
|
if proc > 0: |
||||||
|
logger.warning('There was a problem building the source ' |
||||||
|
'package for"' + pkg + '"') |
||||||
|
vers = re.search(r'[\w-]+-([\d\w\._]+-[\d])-(?:i686|x86_64)', bpkg) |
||||||
|
if vers: |
||||||
|
proc = subprocess.call('mkdir -p ../../backup/testing/' + |
||||||
|
vers.group(1), shell=True) |
||||||
|
if proc > 1: |
||||||
|
logger.warning('There was an error creating the backup ' |
||||||
|
'directory') |
||||||
|
log('Moving "' + bpkg + '" to "backup/testing/' + vers.group(1) + |
||||||
|
'"') |
||||||
|
proc = subprocess.call('mv ' + bpkg + '* ../../backup/testing/' + |
||||||
|
vers.group(1) + '/', shell=True) |
||||||
|
if proc > 1: |
||||||
|
logger.warning('There was a problem copying the package to ' |
||||||
|
'the backup directory') |
||||||
|
source = glob.glob('*.src.tar.gz') |
||||||
|
if source: |
||||||
|
source = source[0] |
||||||
|
else: |
||||||
|
source = '' |
||||||
|
proc = subprocess.call('mv ' + source + ' ../../backup/testing/x86_64/' |
||||||
|
+ vers.group(1) + '/', shell=True) |
||||||
|
if proc > 1: |
||||||
|
logger.warning('There was a problem copying the package source to ' |
||||||
|
'the backup directory') |
||||||
|
# Cleanup |
||||||
|
proc = subprocess.call('rm -r *.log src/', shell=True) |
||||||
|
if proc > 1: |
||||||
|
logger.warning('There was a problem cleaning the working files') |
||||||
|
|
||||||
|
os.chdir('../../') |
@ -1,109 +0,0 @@ |
|||||||
#!/bin/sh |
|
||||||
|
|
||||||
unset ALL_OFF BOLD BLUE GREEN RED YELLOW |
|
||||||
if [[ -t 2 && ! $USE_COLOR = "n" ]]; then |
|
||||||
# prefer terminal safe colored and bold text when tput is supported |
|
||||||
if tput setaf 0 &>/dev/null; then |
|
||||||
ALL_OFF="$(tput sgr0)" |
|
||||||
BOLD="$(tput bold)" |
|
||||||
BLUE="${BOLD}$(tput setaf 4)" |
|
||||||
GREEN="${BOLD}$(tput setaf 2)" |
|
||||||
RED="${BOLD}$(tput setaf 1)" |
|
||||||
YELLOW="${BOLD}$(tput setaf 3)" |
|
||||||
else |
|
||||||
ALL_OFF="\e[1;0m" |
|
||||||
BOLD="\e[1;1m" |
|
||||||
BLUE="${BOLD}\e[1;34m" |
|
||||||
GREEN="${BOLD}\e[1;32m" |
|
||||||
RED="${BOLD}\e[1;31m" |
|
||||||
YELLOW="${BOLD}\e[1;33m" |
|
||||||
fi |
|
||||||
fi |
|
||||||
readonly ALL_OFF BOLD BLUE GREEN RED YELLOW |
|
||||||
|
|
||||||
plain() { |
|
||||||
local mesg=$1; shift |
|
||||||
printf "${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2 |
|
||||||
} |
|
||||||
|
|
||||||
msg() { |
|
||||||
local mesg=$1; shift |
|
||||||
printf "${GREEN}==>${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2 |
|
||||||
} |
|
||||||
|
|
||||||
msg2() { |
|
||||||
local mesg=$1; shift |
|
||||||
printf "${BLUE} ->${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2 |
|
||||||
} |
|
||||||
|
|
||||||
warning() { |
|
||||||
local mesg=$1; shift |
|
||||||
printf "${YELLOW}==> WARNING:${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2 |
|
||||||
} |
|
||||||
|
|
||||||
error() { |
|
||||||
local mesg=$1; shift |
|
||||||
printf "${RED}==> ERROR:${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2 |
|
||||||
} |
|
||||||
|
|
||||||
chroot_build() { |
|
||||||
awk -v newsums="$(makepkg -g)" ' |
|
||||||
BEGIN { |
|
||||||
if (!newsums) exit 1 |
|
||||||
} |
|
||||||
|
|
||||||
/^[[:blank:]]*(md|sha)[[:digit:]]+sums=/,/\)[[:blank:]]*$/ { |
|
||||||
if (!i) print newsums; i++ |
|
||||||
next |
|
||||||
} |
|
||||||
|
|
||||||
1 |
|
||||||
' PKGBUILD > PKGBUILD.new && mv PKGBUILD{.new,} |
|
||||||
sudo makechrootpkg -r /opt/chroot/extra-x86_64 -l zfs64 -- -i |
|
||||||
if [[ $? != "0" ]]; then |
|
||||||
error "Failed building \"${1}\"" |
|
||||||
exit 1; |
|
||||||
fi |
|
||||||
gpg --detach-sign -u 0EE7A126 --use-agent ${1}-*.pkg.tar.xz |
|
||||||
if [[ $? != "0" ]]; then |
|
||||||
warning "Failed signing \"${1}\"" |
|
||||||
return 2; |
|
||||||
fi |
|
||||||
makepkg -Sfc |
|
||||||
if [[ $? != "0" ]]; then |
|
||||||
warning "Failed creating package sources for \"${1}\"" |
|
||||||
return 3; |
|
||||||
fi |
|
||||||
} |
|
||||||
|
|
||||||
mkdir -p backup/new/{x86_64,i686,sources} |
|
||||||
|
|
||||||
packages="spl-utils spl zfs-utils zfs" |
|
||||||
|
|
||||||
for pkg in $packages; do |
|
||||||
cd "devsrc/${pkg}" |
|
||||||
msg "Building ${pkg}" |
|
||||||
chroot_build "${pkg}" |
|
||||||
cd ../../ |
|
||||||
done |
|
||||||
|
|
||||||
msg "Moving sources to backup/new/sources" |
|
||||||
find devsrc/ -type f -iname '*.src.tar*' -exec mv {} backup/new/sources/ \; |
|
||||||
|
|
||||||
msg "Moving x86_64 packages to backup/new/x86_64" |
|
||||||
find devsrc/ -type f -iname '*x86_64.pkg.tar*' -exec mv {} backup/new/x86_64/ \; |
|
||||||
|
|
||||||
msg "Rotating backup archives" |
|
||||||
mv backup/latest/sources/* backup/sources/ |
|
||||||
mv backup/new/sources/* backup/latest/sources/ |
|
||||||
mv backup/latest/x86_64/* backup/packages/x86_64/ |
|
||||||
mv backup/new/x86_64/* backup/latest/x86_64/ |
|
||||||
rm -rf backup/new |
|
||||||
|
|
||||||
msg "Copying packages to the repository directories" |
|
||||||
cp backup/latest/x86_64/* x86_64/ |
|
||||||
|
|
||||||
msg "Adding packages to the repository" |
|
||||||
NPKGS=$(find backup/latest/x86_64/ -type f -iname '*.pkg.tar.xz' -printf "%f ") |
|
||||||
cd x86_64/ |
|
||||||
repo-add -s -v -d archzfs.db.tar.xz $NPKGS |
|
Loading…
Reference in new issue