Newer
Older
# coding: utf-8
# archversion - Archlinux Version Controller
# Copyright © 2012 Sébastien Luttringer
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
'''Archlinux Version Controller'''
from archversion.error import BaseError, MissingConfigFile, NoSuchFile
from archversion.error import ERR_FATAL, ERR_ABORT
from archversion.pacman import parse_pkgbuild, pkgbuild_set_version, pkgbuild_update_checksums
from archversion.version import VersionController
from smtplib import SMTP, SMTP_SSL
def parse_argv():
'''Parse command line arguments'''
p_main = argparse.ArgumentParser()
p_main.add_argument("--version", action="version",
p_main.add_argument("--debug", action="store_true",
help="debug mode")
sp_main = p_main.add_subparsers()
help="list configured packages")
p_conf.add_argument("-s", "--sort", action="store_true",
help="sort listing")
p_conf.add_argument("packages", nargs='*', help="only check these packages")
# sync parser
p_sync = sp_main.add_parser("sync",
help="retrieve upstream and dowstream versions")
p_sync.add_argument("-s", "--sort", action="store_true",
help="sort syncing")
p_sync.add_argument("packages", nargs='*', help="only sync these packages")
p_sync.set_defaults(func=command_sync)
help="list check against modes")
p_modes.set_defaults(func=command_modes)
p_report.add_argument("-f", "--fresh", action="store_true",
help="Only report fresh versions")
p_report.add_argument("-n", "--new", action="store_true",
help="Only report new versions")
p_report.add_argument("-s", "--sort", action="store_true",
help="sync packages versions before report")
p_report.add_argument("packages", nargs='*',
help="only report these packages")
p_report.set_defaults(func=command_report)
# check parser
p_check = sp_main.add_parser("check",
help="check packages versions")
p_check.add_argument("-f", "--fresh", action="store_true",
help="Only report fresh versions")
p_check.add_argument("-n", "--new", action="store_true",
help="Only report new versions")
p_check.add_argument("-s", "--sort", action="store_true",
help="sort packages by name")
p_check.add_argument("packages", nargs='*',
help="only check these packages")
p_check.set_defaults(func=command_check)
# sendmail parser
p_sendmail = sp_main.add_parser("sendmail",
help="sendmail packages versions by mail")
p_sendmail.add_argument("-f", "--fresh", action="store_true",
help="Only sendmail fresh versions")
p_sendmail.add_argument("-n", "--new", action="store_true",
help="Only sendmail new versions")
p_sendmail.add_argument("-s", "--sort", action="store_true",
help="sort packages by name")
p_sendmail.add_argument("-S", "--sync", action="store_true",
help="sync packages versions before sendmail")
p_sendmail.add_argument("--to", help="mail destination address")
p_sendmail.add_argument("--smtp", help="smtp server")
p_sendmail.add_argument("packages", nargs='*',
help="only sendmail these packages")
p_sendmail.set_defaults(func=command_sendmail)
help="update a PKGBUILD with the latest version")
p_update.add_argument("-p", "--path", default="PKGBUILD",
help="name of the file to update. Default PKGBUILD")
p_update.add_argument("-v", "--vars", action="store_true",
help="print variables extracted from the PKGBUILD")
p_update.add_argument("-c", "--checksum", action="store_true",
help="run updpkgsums after update")
p_update.add_argument("-S", "--no-sync", action="store_true",
namespace = p_main.parse_args()
# Ensure subparser was choosen
if "func" not in namespace:
p_main.error("missing argument")
return namespace
def command_config(args, vctrl):
'''list configured packages'''
if len(args.packages) > 0:
vctrl.print_names()
def command_modes(args, vctrl):
'''list checking against modes'''
vctrl.print_modes()
def command_sync(args, vctrl):
'''Handle sync command call'''
# reduce the package list
if len(args.packages) > 0:
def command_check(args, vctrl):
'''Handle check command call'''
# reduce the package list
args.sync=True
command_report(args, vctrl)
def command_report(args, vctrl):
'''Handle report command call'''
# start report
vctrl.print_versions(args.new, args.fresh)
def command_sendmail(args, vctrl):
'''Handle sendmail command call'''
# load sendmail config
config = BaseConfigFile(CONFIG_SENDMAIL)
from_ = config["mail"].get("from", "archversion")
subject = config["mail"].get("subject", "Archversion Report")
host = config["smtp"]["host"]
port = config["smtp"].get("port", "25")
login = config["smtp"].get("login")
password = config["smtp"].get("password")
tls = config["smtp"].get("tls", "no").lower()
raise BaseError("Unable to load sendmail config") from exp
# check tls param
tls_values = ("yes", "no", "starttls")
if tls not in tls_values:
raise BaseError("Invalid SMTP tls value: %s. Should be %s." % (tls, "|".join(tls_values)))
# capture a report
stdout = StringIO()
stdout_bak = sys.stdout
sys.stdout = stdout
command_report(args, vctrl)
sys.stdout = stdout_bak
# no data, no mail!
if len(stdout.getvalue()) == 0:
return
# format the mail
msg = MIMEText(stdout.getvalue())
msg["To"] = to
msg["Date"] = formatdate(localtime=True)
con = SMTP_SSL() if tls == "yes" else SMTP()
# since python3.7 we need to set host to establish ssl/tls connections
# this cannot be done in SMTP class contructor because it try to
# initiate the connection at that time
con._host = host
con.connect(host, port)
if tls == "starttls":
con.starttls()
con.login(login, password)
con.send_message(msg)
con.quit()
def command_update(args, vctrl):
'''Handle update command call'''
if not os.path.exists(args.path):
raise NoSuchFile(args.path)
if os.getresuid()[1] == 0:
logging.warn("Warning: You should not run this as root")
pkgdict = parse_pkgbuild(args.path)
pkgbase = pkgdict.get("pkgbase", None)
pkgname0 = pkgdict.get("pkgname0", None)
pkgver = pkgdict.get("pkgver", None)
# some sanity checks
if pkgname0 is None and pkgbase is None:
raise BaseError("Unable to detect pkgname/pkgbase in %s" % args.path)
if pkgname0 in vctrl.packages:
pkgname = pkgname0
elif pkgbase in vctrl.packages:
pkgname = pkgbase
else:
raise BaseError("No registered package %s" % (pkgbase or pkgname0))
# redure packge list to the extracted one
if upver is None:
raise BaseError("Unable to detect upstream version of %s" % pkgname)
# print what we detect
print("Package name: %s" % pkgname)
print("PKGBUILD version: %s" % pkgver)
print("Version are the same. Do nothing!")
return
# update version with upstream
pkgbuild_set_version(args.path, upver)
# update checksum
if args.checksum:
pkgbuild_update_checksums(args.path)
def main():
'''Program entry point'''
try:
# parse command line
args = parse_argv()
# set global debug mode
if args.debug:
logging.getLogger().setLevel(logging.DEBUG)
# call command function
return args.func(args, vctrl)
except KeyboardInterrupt:
exit(ERR_ABORT)
if logging.getLogger().getEffectiveLevel() == logging.DEBUG:
raise