#!/usr/bin/python3 # # This file is part of FreedomBox. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # """ Configuration helper for Gitweb. """ import argparse import configparser import json import os import shutil import subprocess from plinth import action_utils from plinth.modules.gitweb.forms import validate_repository from plinth.modules.gitweb.manifest import GIT_REPO_PATH def parse_arguments(): """Return parsed command line arguments as dictionary.""" parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') subparsers.add_parser( 'setup', help='Perform post-installation operations for Gitweb') subparser = subparsers.add_parser('create-repo', help='Create a new repository') subparser.add_argument('--name', required=True, help='Name of the repository') subparser.add_argument('--description', required=True, help='Description of the repository') subparser.add_argument('--owner', required=True, help='Repository’s owner name') subparser.add_argument( '--is-private', required=False, default=False, action='store_true', help='Allow only authorized users to access this repository') subparser.add_argument( '--keep-ownership', required=False, default=False, action="store_true", help='Do not chanege ownership of the repository directory') subparser = subparsers.add_parser( 'repo-info', help='Get information about the repository') subparser.add_argument('--name', required=True, help='Name of the repository') subparser = subparsers.add_parser('rename-repo', help='Rename an repository') subparser.add_argument('--oldname', required=True, help='Old name of the repository') subparser.add_argument('--newname', required=True, help='New name of the repository') subparser = subparsers.add_parser('set-repo-description', help='Set description of the repository') subparser.add_argument('--name', required=True, help='Name of the repository') subparser.add_argument('--description', required=True, help='Description of the repository') subparser = subparsers.add_parser('set-repo-owner', help='Set repository\'s owner name') subparser.add_argument('--name', required=True, help='Name of the repository') subparser.add_argument('--owner', required=True, help='Repository’s owner name') subparser = subparsers.add_parser( 'set-repo-access', help='Set repository as private or public') subparser.add_argument('--name', required=True, help='Name of the repository') subparser.add_argument('--access', required=True, choices=['public', 'private'], help='Access status') subparser = subparsers.add_parser('delete-repo', help='Delete an existing repository') subparser.add_argument('--name', required=True, help='Name of the repository to remove') subparsers.required = True return parser.parse_args() def subcommand_setup(_): """Disable default Apache2 Gitweb configuration""" action_utils.webserver_disable('gitweb') def _get_repo_description(repo): """Set description of the repository.""" description_file = os.path.join(GIT_REPO_PATH, repo + '.git', 'description') if os.path.exists(description_file): with open(description_file, 'r') as file_handle: description = file_handle.read() else: description = '' return description def _set_repo_description(repo, description): """Set description of the repository.""" description_file = os.path.join(GIT_REPO_PATH, repo + '.git', 'description') with open(description_file, 'w') as file_handle: file_handle.write(description) def _get_repo_owner(repo): """Set repository's owner name.""" repo_config = os.path.join(GIT_REPO_PATH, repo + '.git', 'config') config = configparser.ConfigParser() config.read(repo_config) try: owner = config['gitweb']['owner'] except KeyError: owner = '' return owner def _set_repo_owner(repo, owner): """Set repository's owner name.""" repo_config = os.path.join(GIT_REPO_PATH, repo + '.git', 'config') config = configparser.ConfigParser() config.read(repo_config) if not config.has_section('gitweb'): config.add_section('gitweb') config['gitweb']['owner'] = owner with open(repo_config, 'w') as file_handle: config.write(file_handle) def _get_access_status(repo): """Get repository's access status""" private_file = os.path.join(GIT_REPO_PATH, repo + '.git', 'private') if os.path.exists(private_file): return 'private' return 'public' def _set_access_status(repo, status): """Set repository as private or public""" private_file = os.path.join(GIT_REPO_PATH, repo + '.git', 'private') if status == 'private': open(private_file, 'a') elif status == 'public': if os.path.exists(private_file): os.remove(private_file) def subcommand_rename_repo(arguments): """Rename a repository.""" validate_repository(arguments.oldname) validate_repository(arguments.newname) oldpath = os.path.join(GIT_REPO_PATH, arguments.oldname + '.git') newpath = os.path.join(GIT_REPO_PATH, arguments.newname + '.git') os.rename(oldpath, newpath) def subcommand_set_repo_description(arguments): """Set description of the repository.""" validate_repository(arguments.name) _set_repo_description(arguments.name, arguments.description) def subcommand_set_repo_owner(arguments): """Set repository's owner name.""" validate_repository(arguments.name) _set_repo_owner(arguments.name, arguments.owner) def subcommand_set_repo_access(arguments): """Set repository's access status.""" validate_repository(arguments.name) _set_access_status(arguments.name, arguments.access) def subcommand_repo_info(arguments): """Get information about repository.""" validate_repository(arguments.name) repo_path = os.path.join(GIT_REPO_PATH, arguments.name + '.git') if not os.path.exists(repo_path): raise RuntimeError('Repository not found') print( json.dumps( dict(name=arguments.name, description=_get_repo_description( arguments.name), owner=_get_repo_owner(arguments.name), access=_get_access_status(arguments.name)))) def subcommand_create_repo(arguments): """Create a new git repository.""" validate_repository(arguments.name) repo_name = arguments.name + '.git' subprocess.check_call(['git', 'init', '--bare', repo_name], cwd=GIT_REPO_PATH) if not arguments.keep_ownership: subprocess.check_call(['chown', '-R', 'www-data:www-data', repo_name], cwd=GIT_REPO_PATH) _set_repo_description(arguments.name, arguments.description) _set_repo_owner(arguments.name, arguments.owner) if arguments.is_private: _set_access_status(arguments.name, 'private') def subcommand_delete_repo(arguments): """Delete a git repository.""" validate_repository(arguments.name) repo_path = os.path.join(GIT_REPO_PATH, arguments.name + '.git') shutil.rmtree(repo_path) def main(): """Parse arguments and perform all duties.""" arguments = parse_arguments() subcommand = arguments.subcommand.replace('-', '_') subcommand_method = globals()['subcommand_' + subcommand] subcommand_method(arguments) if __name__ == '__main__': main()