#!/usr/bin/env python3
#
# Copyright (c) 2015 Jon Turney
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#

#
# create maintainer upload directories
#
# a re-implementation of the mkpkgdir perl script in python
# intended to be run from crontab every 5 minutes
#
# - Read existing maintainer directories, build a list of maintainer
# - Read cygwin-pkg-maint, add to list of maintainers, and build a list of
#   packages for each maintainer
# - Assign orpahaned packages to the project lead(s)
# - For each maintainer, create a home directory, set permissions, and write a
#   !packages file
# - Report if the maintainer has no packages and mark with !defunct
#

import argparse
import grp
import logging
import os
import pwd
import re
import sys

import common_constants
import maintainers

#
#
#

cygwin_uid = pwd.getpwnam('cygwin').pw_uid
cygstage_gid = grp.getgrnam('cygstage').gr_gid

# different values to be used when we are not running on sourceware.org, but my
# test system...
if os.uname()[1] == 'tambora':
    cygwin_uid = pwd.getpwnam('jon').pw_uid
    cygstage_gid = grp.getgrnam('None').gr_gid


#
#
#

def main(args):
    # clear the umask in case it is set
    os.umask(0)

    # create maintainer list
    mlist = {}
    mlist = maintainers.add_directories(mlist, args.homedir)
    mlist = maintainers.add_packages(mlist, args.pkglist, args.orphanmaint)

    # create or suggest removal for each maintainer directory
    for name in sorted(mlist.keys()):
        m = mlist[name]
        dirpath = m.homedir()

        # if the path exists, but isn't a directory
        if os.path.exists(dirpath) and not os.path.isdir(dirpath):
            logging.error("%s exists and isn't a directory!" % dirpath)
            continue

        # ensure the upload directory exists, with appropriate permissions, owner and contents
        logging.info('processing %s' % dirpath)
        if not args.dryrun:
            os.makedirs(dirpath, exist_ok=True)
            os.chown(dirpath, cygwin_uid, cygstage_gid)
            os.chmod(dirpath, 0o2775)
            # write !packages file (we don't use this for anything anymore, but
            # keep it around for information)
            with open(os.path.join(dirpath, '!packages'), 'w') as fd:
                os.fchown(fd.fileno(), cygwin_uid, cygstage_gid)
                print('|'.join([re.escape(p) for p in m.pkgs]), file=fd)
            # and create arch subdirectories, with appropriate owner
            for subdir in common_constants.ARCHES:
                os.makedirs(os.path.join(dirpath, subdir, 'release'), exist_ok=True)
                os.chown(os.path.join(dirpath, subdir, 'release'), cygwin_uid, cygstage_gid)

        # create/remove !defunct as appropriate
        defunct = os.path.join(dirpath, '!defunct')
        if len(m.pkgs) == 0:
            # if they have no packages, suggest removing their upload directory (once)
            if not os.path.exists(defunct):
                logging.warning("defunct maintainer %s, consider removing their directory?" % name)
                if not args.dryrun:
                    open(defunct, 'w').close()
        else:
            # remove defunct marker if no longer defunct
            if os.path.exists(defunct):
                logging.info("maintainer %s no longer defunct" % name)
                if not args.dryrun:
                    os.unlink(defunct)


#
#
#

if __name__ == "__main__":
    homedir_default = common_constants.HOMEDIR
    orphanmaint_default = common_constants.ORPHANMAINT
    pkglist_default = common_constants.PKGMAINT

    parser = argparse.ArgumentParser(description='Create maintainer upload directories')
    parser.add_argument('--homedir', action='store', metavar='DIR', help="maintainer home directory (default: " + homedir_default + ")", default=homedir_default)
    parser.add_argument('--orphanmaint', action='store', metavar='NAMES', help="orphan package maintainers (default: '" + orphanmaint_default + "')", default=orphanmaint_default)
    parser.add_argument('--pkglist', action='store', metavar='FILE', help="package maintainer list (default: " + pkglist_default + ")", default=pkglist_default)
    parser.add_argument('-n', '--dry-run', action='store_true', dest='dryrun', help="don't do anything")
    parser.add_argument('-v', '--verbose', action='count', dest='verbose', help='verbose output')
    (args) = parser.parse_args()

    if args.verbose:
        logging.getLogger().setLevel(logging.INFO)

    logging.basicConfig(format=os.path.basename(sys.argv[0]) + ': %(message)s')

    main(args)
