From ac5458e95360c2392ffb74eb2e4966968ed2009a Mon Sep 17 00:00:00 2001 From: Chenxiong Qi Date: Sep 30 2016 09:54:55 +0000 Subject: New source code layout Configuration file, shell completion scripts, executables and manpage generation script are moved to dedicated directory. Signed-off-by: Chenxiong Qi --- diff --git a/MANIFEST.in b/MANIFEST.in index 7b296aa..1721f09 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,5 @@ include COPYING -include src/_fedpkg -include src/fedpkg.bash -include src/fedpkg.conf -include src/fedpkg_man_page.py +include doc/fedpkg_man_page.py include test/fedpkg-test.conf +include bin/fedpkg bin/fedpkg-stage +recursive-include conf * diff --git a/bin/fedpkg b/bin/fedpkg new file mode 100755 index 0000000..bc2846d --- /dev/null +++ b/bin/fedpkg @@ -0,0 +1,16 @@ +#!/usr/bin/python +# fedpkg - a script to interact with the Fedora Packaging system +# +# Copyright (C) 2011 Red Hat Inc. +# Author(s): Jesse Keating +# +# 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. See http://www.gnu.org/copyleft/gpl.html for +# the full text of the license. + +from fedpkg.__main__ import main + +if __name__ == "__main__": + main() diff --git a/bin/fedpkg-stage b/bin/fedpkg-stage new file mode 100644 index 0000000..b7bdb34 --- /dev/null +++ b/bin/fedpkg-stage @@ -0,0 +1,16 @@ +#!/usr/bin/python +# fedpkg-stage - a script to interact with the Fedora Packaging system +# +# Copyright (C) 2016 Red Hat Inc. +# Author(s): Chenxiong Qi +# +# 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. See http://www.gnu.org/copyleft/gpl.html for +# the full text of the license. + +from fedpkg.__main__ import main + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/conf/bash-completion/fedpkg.bash b/conf/bash-completion/fedpkg.bash new file mode 100644 index 0000000..a7ae59e --- /dev/null +++ b/conf/bash-completion/fedpkg.bash @@ -0,0 +1,322 @@ +# fedpkg bash completion + +_fedpkg() +{ + COMPREPLY=() + + in_array() + { + local i + for i in $2; do + [[ $i = $1 ]] && return 0 + done + return 1 + } + + _filedir_exclude_paths() + { + _filedir "$@" + for ((i=0; i<=${#COMPREPLY[@]}; i++)); do + [[ ${COMPREPLY[$i]} =~ /?\.git/? ]] && unset COMPREPLY[$i] + done + } + + local cur prev + # _get_comp_words_by_ref is in bash-completion >= 1.2, which EL-5 lacks. + if type _get_comp_words_by_ref &>/dev/null; then + _get_comp_words_by_ref cur prev + else + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + fi + + # global options + + local options="--help -v -q" + local options_value="--dist --user --path" + local commands="build chain-build ci clean clog clone co commit compile \ + container-build diff gimmespec giturl help gitbuildhash import install lint \ + local mockbuild mock-config new new-sources patch prep pull push retire \ + scratch-build sources srpm switch-branch tag unused-patches update upload \ + verify-files verrel" + + # parse main options and get command + + local command= + local command_first= + local path= + + local i w + for (( i = 0; i < ${#COMP_WORDS[*]} - 1; i++ )); do + w="${COMP_WORDS[$i]}" + # option + if [[ ${w:0:1} = - ]]; then + if in_array "$w" "$options_value"; then + ((i++)) + [[ "$w" = --path ]] && path="${COMP_WORDS[$i]}" + fi + # command + elif in_array "$w" "$commands"; then + command="$w" + command_first=$((i+1)) + break + fi + done + + # complete base options + + if [[ -z $command ]]; then + if [[ $cur == -* ]]; then + COMPREPLY=( $(compgen -W "$options $options_value" -- "$cur") ) + return 0 + fi + + case "$prev" in + --dist) + ;; + --user|-u) + ;; + --path) + _filedir_exclude_paths + ;; + *) + COMPREPLY=( $(compgen -W "$commands" -- "$cur") ) + ;; + esac + + return 0 + fi + + # parse command specific options + + local options= + local options_target= options_arches= options_branch= options_string= options_file= options_dir= options_srpm= options_mroot= options_builder= + local after= after_more= + + case $command in + help|gimmespec|gitbuildhash|giturl|lint|new|push|unused-patches|update|verrel) + ;; + build) + options="--nowait --background --skip-tag --scratch" + options_srpm="--srpm" + options_target="--target" + ;; + chain-build) + options="--nowait --background" + options_target="--target" + after="package" + after_more=true + ;; + clean) + options="--dry-run -x" + ;; + clog) + options="--raw" + ;; + clone|co) + options="--branches --anonymous" + options_branch="-b" + after="package" + ;; + commit|ci) + options="--push --clog --raw --tag" + options_string="--message" + options_file="--file" + after="file" + after_more=true + ;; + compile|install) + options="--short-circuit" + options_arch="--arch" + options_dir="--builddir" + ;; + container-build) + options="--scratch" + options_target="--target" + options_builder="--build-with" + ;; + diff) + options="--cached" + after="file" + after_more=true + ;; + import) + options="--create" + options_branch="--branch" + after="srpm" + ;; + lint) + options="--info" + ;; + local) + options="--md5" + options_arch="--arch" + options_dir="--builddir" + ;; + mock-config) + options="--target" + options_arch="--arch" + ;; + mockbuild) + options="--md5 --no-clean --no-cleanup-after --no-clean-all" + options_mroot="--root" + ;; + patch) + options="--rediff" + options_string="--suffix" + ;; + prep|verify-files) + options_arch="--arch" + options_dir="--builddir" + ;; + pull) + options="--rebase --no-rebase" + ;; + retire) + after_more=true + ;; + scratch-build) + options="--nowait --background" + options_target="--target" + options_arches="--arches" + options_srpm="--srpm" + ;; + sources) + options_dir="--outdir" + ;; + srpm) + options="--md5" + ;; + switch-branch) + options="--list" + after="branch" + ;; + tag) + options="--clog --raw --force --list --delete" + options_string="--message" + options_file="--file" + after_more=true + ;; + upload|new-sources) + after="file" + after_more=true + ;; + esac + + local all_options="--help $options" + local all_options_value="$options_target $options_arches $options_branch $options_string $options_file $options_dir $options_srpm $options_mroot $options_builder" + + # count non-option parameters + + local i w + local last_option= + local after_counter=0 + for (( i = $command_first; i < ${#COMP_WORDS[*]} - 1; i++)); do + w="${COMP_WORDS[$i]}" + if [[ ${w:0:1} = - ]]; then + if in_array "$w" "$all_options"; then + last_option="$w" + continue + elif in_array "$w" "$all_options_value"; then + last_option="$w" + ((i++)) + continue + fi + fi + in_array "$last_option" "$options_arches" || ((after_counter++)) + done + + # completion + + if [[ -n $options_target ]] && in_array "$prev" "$options_target"; then + COMPREPLY=( $(compgen -W "$(_fedpkg_target)" -- "$cur") ) + + elif [[ -n $options_arches ]] && in_array "$last_option" "$options_arches"; then + COMPREPLY=( $(compgen -W "$(_fedpkg_arch) $all_options" -- "$cur") ) + + elif [[ -n $options_builder ]] && in_array "$prev" "$options_builder"; then + COMPREPLY=( $(compgen -W "$(_fedpkg_builder)" -- "$cur") ) + + elif [[ -n $options_srpm ]] && in_array "$prev" "$options_srpm"; then + _filedir_exclude_paths "*.src.rpm" + + elif [[ -n $options_branch ]] && in_array "$prev" "$options_branch"; then + COMPREPLY=( $(compgen -W "$(_fedpkg_branch "$path")" -- "$cur") ) + + elif [[ -n $options_file ]] && in_array "$prev" "$options_file"; then + _filedir_exclude_paths + + elif [[ -n $options_dir ]] && in_array "$prev" "$options_dir"; then + _filedir_exclude_paths -d + + elif [[ -n $options_string ]] && in_array "$prev" "$options_string"; then + COMPREPLY=( ) + + elif [[ -n $options_mroot ]] && in_array "$prev" "$options_mroot"; then + COMPREPLY=( ) + if declare -F _mock_root &>/dev/null; then + _mock_root + elif declare -F _xfunc &>/dev/null; then + _xfunc mock _mock_root + fi + + else + local after_options= + + if [[ $after_counter -eq 0 ]] || [[ $after_more = true ]]; then + case $after in + file) _filedir_exclude_paths ;; + srpm) _filedir_exclude_paths "*.src.rpm" ;; + branch) after_options="$(_fedpkg_branch "$path")" ;; + package) after_options="$(_fedpkg_package "$cur")";; + esac + fi + + if [[ $cur != -* ]]; then + all_options= + all_options_value= + fi + + COMPREPLY+=( $(compgen -W "$all_options $all_options_value $after_options" -- "$cur" ) ) + fi + + return 0 +} && +complete -F _fedpkg fedpkg + +_fedpkg_target() +{ + koji list-targets --quiet 2>/dev/null | cut -d" " -f1 +} + +_fedpkg_arch() +{ + echo "i386 i686 x86_64 armv5tel armv7hl armv7hnl ppc ppc64 ppc64p7 s390 s390x" +} + +_fedpkg_builder() +{ + echo "koji osbs" +} + +_fedpkg_branch() +{ + local git_options= format="--format %(refname:short)" + [[ -n $1 ]] && git_options="--git-dir=$1/.git" + + git $git_options for-each-ref $format 'refs/remotes' | sed 's,.*/,,' + git $git_options for-each-ref $format 'refs/heads' +} + +_fedpkg_package() +{ + repoquery -C --qf=%{sourcerpm} "$1*" 2>/dev/null | sort -u | sed -r 's/(-[^-]*){2}\.src\.rpm$//' +} + +# Local variables: +# mode: shell-script +# sh-basic-offset: 4 +# sh-indent-comment: t +# indent-tabs-mode: nil +# End: +# ex: ts=4 sw=4 et filetype=sh diff --git a/conf/etc/rpkg/fedpkg-stage.conf b/conf/etc/rpkg/fedpkg-stage.conf new file mode 100644 index 0000000..f192895 --- /dev/null +++ b/conf/etc/rpkg/fedpkg-stage.conf @@ -0,0 +1,24 @@ +[fedpkg-stage] +lookaside = http://pkgs.stg.fedoraproject.org/repo/pkgs +lookasidehash = md5 +lookaside_cgi = https://pkgs.stg.fedoraproject.org/repo/pkgs/upload.cgi +gitbaseurl = ssh://%(user)s@pkgs.stg.fedoraproject.org/%(module)s +anongiturl = git://pkgs.stg.fedoraproject.org/%(module)s +tracbaseurl = https://%(user)s:%(password)s@fedorahosted.org/rel-eng/login/xmlrpc +branchre = f\d$|f\d\d$|el\d$|olpc\d$|master$ +kojiconfig = /etc/koji/stg-config +build_client = koji +clone_config = + bz.default-tracker partner-bugzilla.redhat.com + bz.default-product Fedora + bz.default-version rawhide + bz.default-component %(module)s + sendemail.to %(module)s-owner@fedoraproject.org + push.default simple +distgit_namespaced = True + +[fedpkg-stage.bodhi] +url = https://bodhi.stg.fedoraproject.org/ + +[fedpkg-stage.pkgdb] +url = https://admin.stg.fedoraproject.org/pkgdb/ \ No newline at end of file diff --git a/conf/etc/rpkg/fedpkg.conf b/conf/etc/rpkg/fedpkg.conf new file mode 100644 index 0000000..b0d132c --- /dev/null +++ b/conf/etc/rpkg/fedpkg.conf @@ -0,0 +1,24 @@ +[fedpkg] +lookaside = http://pkgs.fedoraproject.org/repo/pkgs +lookasidehash = md5 +lookaside_cgi = https://pkgs.fedoraproject.org/repo/pkgs/upload.cgi +gitbaseurl = ssh://%(user)s@pkgs.fedoraproject.org/%(module)s +anongiturl = git://pkgs.fedoraproject.org/%(module)s +tracbaseurl = https://%(user)s:%(password)s@fedorahosted.org/rel-eng/login/xmlrpc +branchre = f\d$|f\d\d$|el\d$|olpc\d$|master$ +kojiconfig = /etc/koji.conf +build_client = koji +clone_config = + bz.default-tracker bugzilla.redhat.com + bz.default-product Fedora + bz.default-version rawhide + bz.default-component %(module)s + sendemail.to %(module)s-owner@fedoraproject.org + push.default simple +distgit_namespaced = True + +[fedpkg.bodhi] +url = https://bodhi.fedoraproject.org/ + +[fedpkg.pkgdb] +url = https://admin.fedoraproject.org/pkgdb/ \ No newline at end of file diff --git a/conf/zsh-completion/_fedpkg b/conf/zsh-completion/_fedpkg new file mode 100644 index 0000000..ac24300 --- /dev/null +++ b/conf/zsh-completion/_fedpkg @@ -0,0 +1,441 @@ +#compdef fedpkg + +(( $+functions[_fedpkg_targets] )) || +_fedpkg_targets() +{ + local expl + + _wanted koji-targets expl 'target' compadd \ + ${${(f)"$(_call_program koji-targets koji list-targets --quiet 2>/dev/null)"}%% *} +} + +(( $+functions[_fedpkg_arches] )) || +_fedpkg_arches() +{ + local expl + local -a arches + + arches=( /etc/mock/[^-]##-[^-]##-[^-]##.cfg ) + _wanted mock-arches expl 'arch' compadd \ + ${(u)${arches#/etc/mock/[^-]##-[^-]##-}%.cfg} +} + +(( $+functions[_fedpkg_packages] )) || +_fedpkg_packages() +{ + local expl + + _wanted repo-packages expl 'package' compadd \ + ${${(fu)"$(repoquery -Cs -- "$words[CURRENT]*")"}%-[^-]##-[^-]##.src.rpm} +} + +(( $+functions[_fedpkg_branches] )) || +_fedpkg_branches() +{ + local expl + local -a git_opts + local -a branches + + (( ${words[(I)--path]} )) && + git_opts=( --git-dir ${words[${words[(i)--path]}+1]} ) + + branches=(${${(f)"$(git $git_opts for-each-ref --format='%(refname)' refs/heads 2>/dev/null)"}#refs/heads/}) + branches+=(${${(f)"$(git $git_opts for-each-ref --format='%(refname)' refs/remotes 2>/dev/null)"}##refs/remotes/*/}) + + _wanted branch-names expl 'branch-name' compadd \ + ${(u)branches} +} + +(( $+functions[_fedpkg-help] )) || +_fedpkg-help () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' +} + +(( $+functions[_fedpkg-build] )) || +_fedpkg-build () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '--arches[build for specific arches]:*:arch:_fedpkg_arches' \ + '--md5[use md5 checksums]' \ + '--nowait[don'\''t wait on build]' \ + '--target[define build target to build into]:target:_fedpkg_targets' \ + '--background[run the build at a low priority]' \ + '--skip-tag[do not attempt to tag package]' \ + '--scratch[perform a scratch build]' \ + '--srpm[build from an srpm]::srpm:_files -g "*.src.rpm"' +} + +(( $+functions[_fedpkg-chain-build] )) || +_fedpkg-chain-build () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '--arches[build for specific arches]:*:arch:_fedpkg_arches' \ + '--md5[use md5 checksums]' \ + '--nowait[on'\''t wait on build]' \ + '--target[define build target to build into]:target:_fedpkg_targets' \ + '--background[run the build at a low priority]' \ + '*:package:_fedpkg_packages' +} + +(( $+functions[_fedpkg-clean] )) || +_fedpkg-clean () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '(-n --dry-run)'{-n,--dry-run}'[perform a dry-run]' \ + '-x[do not follow .gitignore rules]' +} + +(( $+functions[_fedpkg-clog] )) || +_fedpkg-clog () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '--raw[generate a more "raw" clog without twiddling the contents]' +} + +(( $+functions[_fedpkg-clone] )) || +_fedpkg-clone () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '(-B --branches)'{-B,--branches}'[do an old style checkout with subdirs for branches]' \ + '(-b --branch)'{-b,--branch}'[check out a specific branch]:branch:_fedpkg_branches' \ + '(-a --anonymous)'{-a,--anonymous}'[check out a module anonymously]' \ + ':package:_fedpkg_packages' +} + +(( $+functions[_fedpkg-commit] )) || +_fedpkg-commit () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '(-c --clog)'{-c,--clog}'[generate the commit message from the %changelog section]' \ + '--raw[make the clog raw]' \ + '(-t --tag)'{-t,--tag}'[create a tag for this commit]' \ + '(-m --message)'{-m,--message}'[use the given commit message]:message' \ + '(-F --file)'{-F,--file}'[take the commit message from the given file]:file:_files' \ + '(-p --push)'{-p,--push}'[commit and push as one action]' \ + '*:file:_files' +} + +(( $+functions[_fedpkg-compile] )) || +_fedpkg-compile () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '--builddir[define an alternate builddir]:builddir:_files -/' \ + '--arch[prep for a specific arch]:arch:_fedpkg_arches' \ + '--short-circuit[short-circuit compile]' +} + +(( $+functions[_fedpkg-copr-build] )) || +_fedpkg-copr-build () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '--nowait[on'\''t wait on build]' \ + '*:project' +} + +(( $+functions[_fedpkg-diff] )) || +_fedpkg-diff () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '--cached[view staged changes]' \ + '*:file:_files' +} + +(( $+functions[_fedpkg-gimmespec] )) || +_fedpkg-gimmespec () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' +} + +(( $+functions[_fedpkg-gitbuildhash] )) || +_fedpkg-gitbuildhash () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + ':build' +} + +(( $+functions[_fedpkg-giturl] )) || +_fedpkg-giturl () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' +} + +(( $+functions[_fedpkg-import] )) || +_fedpkg-import () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + ':srpm:_files -g "*.src.rpm"' +} + +(( $+functions[_fedpkg-install] )) || +_fedpkg-install () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '--builddir[define an alternate builddir]:builddir:_files -/' \ + '--arch[prep for a specific arch]:arch:_fedpkg_arches' \ + '--short-circuit[short-circuit compile]' +} + +(( $+functions[_fedpkg-lint] )) || +_fedpkg-lint () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '(-i --info)'{-i,--info}'[display explanations for reported messages]' \ + '(-r --rpmlintconf)'{-r,--rpmlintconf}'[use a specific configuration file for rpmlint]:rpmlintconf:_files' +} + +(( $+functions[_fedpkg-local] )) || +_fedpkg-local () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '--builddir[define an alternate builddir]:builddir:_files -/' \ + '--arch[prep for a specific arch]:arch:_fedpkg_arches' \ + '--md5[use md5 checksums]' +} + +(( $+functions[_fedpkg-mockbuild] )) || +_fedpkg-mockbuild () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '--root[override mock root]:root:_files -/' \ + '--md5[use md5 checksums]' +} + +(( $+functions[_fedpkg-mock-config] )) || +_fedpkg-mock-config () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '--target[override target used for config]:target:_fedpkg_targets' + '--arch[override local arch]:arch:_fedpkg_arches' +} + +(( $+functions[_fedpkg-new] )) || +_fedpkg-new () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' +} + +(( $+functions[_fedpkg-new-sources] )) || +_fedpkg-new-sources () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '*:file:_files' +} + +(( $+functions[_fedpkg-patch] )) || +_fedpkg-patch () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '--rediff[recreate gendiff file retaining comments]' \ + ':suffix' +} + +(( $+functions[_fedpkg-prep] )) || +_fedpkg-prep () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '--builddir[define an alternate builddir]:builddir:_files -/' \ + '--arch[prep for a specific arch]:arch:_fedpkg_arches' +} + +(( $+functions[_fedpkg-pull] )) || +_fedpkg-pull () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '(--no-rebase)--rebase[rebase the locally committed changes on top of the remote changes]' \ + '(--rebase)--no-rebase[do not rebase, override .git settings to automatically rebase]' +} + +(( $+functions[_fedpkg-push] )) || +_fedpkg-push () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' +} + +(( $+functions[_fedpkg-scratch-build] )) || +_fedpkg-scratch-build () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '--arches[build for specific arches]:*:arch:_fedpkg_arches' \ + '--md5[use md5 checksums]' \ + '--nowait[on'\''t wait on build]' \ + '--target[define build target to build into]:target:_fedpkg_targets' \ + '--background[run the build at a low priority]' \ + '--srpm[build from an srpm]::srpm:_files -g "*.src.rpm"' +} + +(( $+functions[_fedpkg-sources] )) || +_fedpkg-sources () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '--outdir[directory to download files into]:outdir:_files -/' +} + +(( $+functions[_fedpkg-srpm] )) || +_fedpkg-srpm () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '--md5[use md5 checksums]' +} + +(( $+functions[_fedpkg-switch-branch] )) || +_fedpkg-switch-branch () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '(: -l --list)'{-l,--list}'[list both remote-tracking branches and local branches]' \ + '(-):branch:_fedpkg_branches' +} + +(( $+functions[_fedpkg-tag] )) || +_fedpkg-tag () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '(-f --force)'{-f,--force}'[force the creation of the tag]' \ + '(-m --message)'{-m,--message}'[use the given commit message]:message' \ + '(-c --clog)'{-c,--clog}'[generate the commit message from the %changelog section]' \ + '--raw[make the clog raw]' \ + '(-F --file)'{-F,--file}'[take the commit message from the given file]:file:_files' \ + '(-l --list)'{-l,--list}'[list all tags with a given pattern]' \ + '(-d --delete)'{-d,--delete}'[delete a tag]' \ + ':tag' +} + +(( $+functions[_fedpkg-unused-patches] )) || +_fedpkg-unused-patches () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' +} + +(( $+functions[_fedpkg-upload] )) || +_fedpkg-upload () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '*:file:_files' +} + +(( $+functions[_fedpkg-verify-files] )) || +_fedpkg-verify-files () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '--builddir[define an alternate builddir]:builddir:_files -/' \ + '--arch[prep for a specific arch]:arch:_fedpkg_arches' +} + +(( $+functions[_fedpkg-verrel] )) || +_fedpkg-verrel () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' +} + +(( $+functions[_fedpkg-retire] )) || +_fedpkg-retire () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' \ + '(-p --push)'{-p,--push}'[push changes to remote repository]' \ + ':message' +} + +(( $+functions[_fedpkg-update] )) || +_fedpkg-update () { + _arguments -C \ + '(-h --help)'{-h,--help}'[show help message and exit]' +} + +(( $+functions[_fedpkg_commands] )) || +_fedpkg_commands () { + local -a fedpkg_commands + fedpkg_commands=( + help:'show usage' + build:'request build' + chain-build:'build current package in order with other packages' + clean:'remove untracked files' + clog:'make a clog file containing top changelog entry' + clone:'clone and checkout a module' + commit:'commit changes' + compile:'local test rpmbuild compile' + copr-build:'build package in Copr' + diff:'show changes between commits, commit and working tree, etc' + gimmespec:'print the spec file name' + gitbuildhash:'print the git hash used to build the provided n-v-r' + giturl:'print the git url for building' + import:'import srpm content into a module' + install:'local test rpmbuild install' + lint:'run rpmlint against local spec and build output if present' + local:'local test rpmbuild binary' + mockbuild:'local test build using mock' + mock-config:'generate a mock config' + new:'diff against last tag' + new-sources:'upload new source files' + patch:'create and add a gendiff patch file' + prep:'local test rpmbuild prep' + pull:'pull changes from remote repository and update working copy' + push:'push changes to remote repository' + scratch-build:'request scratch build' + sources:'download source files' + srpm:'create a source rpm' + switch-branch:'work with branches' + tag:'management of git tags' + unused-patches:'print list of patches not referenced by name in the specfile' + upload:'upload source files' + verify-files:'locally verify %files section' + verrel:'print the name-version-release' + retire:'retire a package' + update:'submit last build as an update' + ) + + integer ret=1 + + # TODO: Is this the correct way of doing it? Should we be using _alternative + # and separate functions for each set of commands instead? + _describe -t fedpkg-commands 'fedpkg command' fedpkg_commands && ret=0 + + return ret +} + +_fedpkg() { + local -A fedpkg_aliases + fedpkg_aliases=( + co clone + ci commit + ) + integer ret=1 + + local curcontext=$curcontext state line + declare -A opt_args + + _arguments -C \ + '(- :)'{-h,--help}'[show help message and exit]' \ + '(-C --config)'{-C,--config}'[specify a config file to use]:config file:_files' \ + '--dist[override the discovered distribution]:distribution' \ + '--user[override the discovered user name]:user' \ + '--path[define the directory to work in (defaults to cwd)]:working direcory:_directories' \ + '(-q)-v[run with verbose debug output]' \ + '(-v)-q[run quietly only displaying errors]' \ + '(-): :->command' \ + '(-)*:: :->option-or-argument' && return + + case $state in + (command) + _fedpkg_commands && ret=0 + ;; + (option-or-argument) + local cmd=$words[1] + (( $+fedpkg_aliases[$cmd] )) && + cmd=$fedpkg_aliases[$cmd] + + curcontext=${curcontext%:*:*}:fedpkg-$cmd: + + if (( $+functions[_fedpkg-$cmd] )); then + _call_function ret _fedpkg-$cmd + elif zstyle -T :completion:$curcontext: use-fallback; then + _files && ret=0 + else + _message 'unknown sub-command' + fi + ;; + esac + + return ret +} + +_fedpkg diff --git a/doc/fedpkg_man_page.py b/doc/fedpkg_man_page.py new file mode 100755 index 0000000..0e7e1f3 --- /dev/null +++ b/doc/fedpkg_man_page.py @@ -0,0 +1,155 @@ +# Print a man page from the help texts. + + +import sys +import datetime + + +# We could substitute the "" in .TH with the fedpkg version if we knew it +man_header = """\ +.\\" man page for fedpkg +.TH fedpkg 1 "%(today)s" "" "RPM packager" +.SH "NAME" +fedpkg \- RPM Packaging utility +.SH "SYNOPSIS" +.B "fedpkg" +[ +.I global_options +] +.I "command" +[ +.I command_options +] +[ +.I command_arguments +] +.br +.B "fedpkg" +.B "help" +.br +.B "fedpkg" +.I "command" +.B "\-\-help" +.SH "DESCRIPTION" +.B "fedpkg" +is a script to interact with the RPM Packaging system. +""" + +man_footer = """\ +.SH "SEE ALSO" +.UR "https://fedorahosted.org/fedora\-packager/" +.BR "https://fedorahosted.org/fedora\-packager/" +""" + + +class ManFormatter(object): + + def __init__(self, man): + self.man = man + + def write(self, data): + # print("MF: %r" % data) + for line in data.split('\n'): + # print('MFL: %s' % line) + self.man.write(' %s\n' % line) + + +def strip_usage(s): + """Strip "usage: " string from beginning of string if present""" + if s.startswith('usage: '): + return s.replace('usage: ', '', 1) + else: + return s + + +def man_constants(): + """Global constants for man file templates""" + today = datetime.date.today() + today_manstr = today.strftime('%Y\-%m\-%d') + return {'today': today_manstr} + + +def generate(parser, subparsers): + """\ + Generate the man page on stdout + + Given the argparse based parser and subparsers arguments, generate + the corresponding man page and write it to stdout. + """ + + # Not nice, but works: Redirect any print statement output to + # stderr to avoid clobbering the man page output on stdout. + man_file = sys.stdout + sys.stdout = sys.stderr + + mf = ManFormatter(man_file) + + choices = subparsers.choices + k = sorted(choices.keys()) + + man_file.write(man_header % man_constants()) + + helptext = parser.format_help() + helptext = strip_usage(helptext) + helptextsplit = helptext.split('\n') + helptextsplit = [line for line in helptextsplit + if not line.startswith(' -h, --help')] + + man_file.write('.SS "%s"\n' % ("Global Options",)) + + outflag = False + for line in helptextsplit: + if line == "optional arguments:": + outflag = True + elif line == "": + outflag = False + elif outflag: + man_file.write("%s\n" % line) + + help_texts = {} + for pa in subparsers._choices_actions: + help_texts[pa.dest] = getattr(pa, 'help', None) + + man_file.write('.SH "COMMAND OVERVIEW"\n') + + for command in k: + cmdparser = choices[command] + if not cmdparser.add_help: + continue + usage = cmdparser.format_usage() + usage = strip_usage(usage) + usage = ''.join(usage.split('\n')) + usage = ' '.join(usage.split()) + if help_texts[command]: + man_file.write('.TP\n.B "%s"\n%s\n' % (usage, help_texts[command])) + else: + man_file.write('.TP\n.B "%s"\n' % (usage)) + + man_file.write('.SH "COMMAND REFERENCE"\n') + for command in k: + cmdparser = choices[command] + if not cmdparser.add_help: + continue + + man_file.write('.SS "%s"\n' % cmdparser.prog) + + help = help_texts[command] + if help and not cmdparser.description: + if not help.endswith('.'): + help = "%s." % help + cmdparser.description = help + + h = cmdparser.format_help() + mf.write(h) + + man_file.write(man_footer) + + +if __name__ == '__main__': + try: + import fedpkg + except ImportError: + sys.path.append('src/') + import fedpkg + client = fedpkg.cli.fedpkgClient(config=None, name='fedpkg') + generate(client.parser, client.subparsers) diff --git a/fedpkg/__init__.py b/fedpkg/__init__.py new file mode 100644 index 0000000..0fae271 --- /dev/null +++ b/fedpkg/__init__.py @@ -0,0 +1,351 @@ +# fedpkg - a Python library for RPM Packagers +# +# Copyright (C) 2011 Red Hat Inc. +# Author(s): Jesse Keating +# +# 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. See http://www.gnu.org/copyleft/gpl.html for +# the full text of the license. + +import pyrpkg +import os +import git +import re +import fedora_cert +import platform +import subprocess + +from . import cli # noqa +from .lookaside import FedoraLookasideCache +from pyrpkg.utils import cached_property + + +class Commands(pyrpkg.Commands): + + def __init__(self, path, lookaside, lookasidehash, lookaside_cgi, + gitbaseurl, anongiturl, branchre, kojiconfig, + build_client, user=None, dist=None, target=None, + quiet=False, distgit_namespaced=False): + """Init the object and some configuration details.""" + + # We are subclassing to set kojiconfig to none, so that we can + # make it a property to potentially use a secondary config + super(Commands, self).__init__(path, lookaside, lookasidehash, + lookaside_cgi, gitbaseurl, anongiturl, + branchre, kojiconfig, build_client, + user=user, dist=dist, target=target, + quiet=quiet, + distgit_namespaced=distgit_namespaced) + + # New data + self.secondary_arch = { + 'ppc': [ + 'apmud', + 'libbsr', + 'librtas', + 'libservicelog', + 'libvpd', + 'lsvpd', + 'powerpc-utils', + 'powerpc-utils-papr', + 'powerpc-utils-python', + 'ppc64-diag', + 'ppc64-utils', + 'servicelog', + 'yaboot', + ], + 'arm': ['xorg-x11-drv-omapfb'], + 's390': ['s390utils', 'openssl-ibmca', 'libica', 'libzfcphbaapi'], + } + + # New properties + self._kojiconfig = None + # Store this for later + self._orig_kojiconfig = kojiconfig + + # Add new properties + @property + def kojiconfig(self): + """This property ensures the kojiconfig attribute""" + + if not self._kojiconfig: + self.load_kojiconfig() + return self._kojiconfig + + @kojiconfig.setter + def kojiconfig(self, value): + self._kojiconfig = value + + def load_kojiconfig(self): + """This loads the kojiconfig attribute + + This will either use the one passed in via arguments or a + secondary arch config depending on the package + """ + + # We have to allow this to work, even if we don't have a package + # we're working on, for things like gitbuildhash. + try: + self.module_name + except: + self._kojiconfig = self._orig_kojiconfig + return + for arch in self.secondary_arch.keys(): + if self.module_name in self.secondary_arch[arch]: + self._kojiconfig = os.path.expanduser('/etc/koji/%s-config' % + arch) + return + self._kojiconfig = self._orig_kojiconfig + + @cached_property + def cert_file(self): + """A client-side certificate for SSL authentication + + We override this from pyrpkg because we actually need a client-side + certificate. + """ + return os.path.expanduser('~/.fedora.cert') + + @cached_property + def ca_cert(self): + """A CA certificate to authenticate the server in SSL connections + + We override this from pyrpkg because we actually need a custom + CA certificate. + """ + return os.path.expanduser('~/.fedora-server-ca.cert') + + @cached_property + def lookasidecache(self): + """A helper to interact with the lookaside cache + + We override this because we need a different download path. + """ + return FedoraLookasideCache( + self.lookasidehash, self.lookaside, self.lookaside_cgi, + client_cert=self.cert_file, ca_cert=self.ca_cert) + + # Overloaded property loaders + def load_rpmdefines(self): + """Populate rpmdefines based on branch data""" + + # Determine runtime environment + self._runtime_disttag = self._determine_runtime_env() + + # We only match the top level branch name exactly. + # Anything else is too dangerous and --dist should be used + # This regex works until after Fedora 99. + if re.match(r'f\d\d$', self.branch_merge): + self._distval = self.branch_merge.split('f')[1] + self._distvar = 'fedora' + self.dist = 'fc%s' % self._distval + self.mockconfig = 'fedora-%s-%s' % (self._distval, self.localarch) + self.override = 'f%s-override' % self._distval + self._distunset = 'rhel' + # Works until RHEL 10 + elif re.match(r'el\d$', self.branch_merge) or \ + re.match(r'epel\d$', self.branch_merge): + self._distval = self.branch_merge.split('el')[1] + self._distvar = 'rhel' + self.dist = 'el%s' % self._distval + self.mockconfig = 'epel-%s-%s' % (self._distval, self.localarch) + self.override = 'epel%s-override' % self._distval + self._distunset = 'fedora' + elif re.match(r'olpc\d$', self.branch_merge): + self._distval = self.branch_merge.split('olpc')[1] + self._distvar = 'olpc' + self.dist = 'olpc%s' % self._distval + self.override = 'dist-olpc%s-override' % self._distval + self._distunset = 'rhel' + # master + elif re.match(r'master$', self.branch_merge): + self._distval = self._findmasterbranch() + self._distvar = 'fedora' + self.dist = 'fc%s' % self._distval + self.mockconfig = 'fedora-rawhide-%s' % self.localarch + self.override = None + self._distunset = 'rhel' + # If we don't match one of the above, punt + else: + raise pyrpkg.rpkgError('Could not find the dist from branch name ' + '%s\nPlease specify with --dist' % + self.branch_merge) + self._rpmdefines = ["--define '_sourcedir %s'" % self.path, + "--define '_specdir %s'" % self.path, + "--define '_builddir %s'" % self.path, + "--define '_srcrpmdir %s'" % self.path, + "--define '_rpmdir %s'" % self.path, + "--define 'dist .%s'" % self.dist, + "--define '%s %s'" % (self._distvar, + self._distval), + "--eval '%%undefine %s'" % self._distunset, + "--define '%s 1'" % self.dist] + if self._runtime_disttag: + if self.dist != self._runtime_disttag: + # This means that the runtime is known, and is different from + # the target, so we need to unset the _runtime_disttag + self._rpmdefines.append("--eval '%%undefine %s'" % + self._runtime_disttag) + + def load_target(self): + """This creates the target attribute based on branch merge""" + + if self.branch_merge == 'master': + self._target = 'rawhide' + else: + self._target = '%s-candidate' % self.branch_merge + + def load_user(self): + """This sets the user attribute, based on the Fedora SSL cert.""" + try: + self._user = fedora_cert.read_user_cert() + except Exception as e: + self.log.debug('Could not read Fedora cert, falling back to ' + 'default method: %s' % e) + super(Commands, self).load_user() + + # New functionality + def _findmasterbranch(self): + """Find the right "fedora" for master""" + + # If we already have a koji session, just get data from the source + if self._kojisession: + rawhidetarget = self.kojisession.getBuildTarget('rawhide') + desttag = rawhidetarget['dest_tag_name'] + return desttag.split('-')[0].replace('f', '') + + # Create a list of "fedoras" + fedoras = [] + + # Create a regex to find branches that exactly match f##. Should not + # catch branches such as f14-foobar + branchre = 'f\d\d$' + + # Find the repo refs + for ref in self.repo.refs: + # Only find the remote refs + if type(ref) == git.RemoteReference: + # Search for branch name by splitting off the remote + # part of the ref name and returning the rest. This may + # fail if somebody names a remote with / in the name... + if re.match(branchre, ref.name.split('/', 1)[1]): + # Add just the simple f## part to the list + fedoras.append(ref.name.split('/')[1]) + if fedoras: + # Sort the list + fedoras.sort() + # Start with the last item, strip the f, add 1, return it. + return(int(fedoras[-1].strip('f')) + 1) + else: + # We may not have Fedoras. Find out what rawhide target does. + try: + rawhidetarget = self.anon_kojisession.getBuildTarget( + 'rawhide') + except: + # We couldn't hit koji, bail. + raise pyrpkg.rpkgError('Unable to query koji to find rawhide \ + target') + desttag = rawhidetarget['dest_tag_name'] + return desttag.replace('f', '') + + def _determine_runtime_env(self): + """Need to know what the runtime env is, so we can unset anything + conflicting + """ + + try: + mydist = platform.linux_distribution() + except: + # This is marked as eventually being deprecated. + try: + mydist = platform.dist() + except: + runtime_os = 'unknown' + runtime_version = '0' + + if mydist: + runtime_os = mydist[0] + runtime_version = mydist[1] + else: + runtime_os = 'unknown' + runtime_version = '0' + + if runtime_os in ['redhat', 'centos']: + return 'el%s' % runtime_version + if runtime_os == 'Fedora': + return 'fc%s' % runtime_version + + # fall through, return None + return None + + def retire(self, message): + """Delete all tracked files and commit a new dead.package file + + Use optional message in commit. + + Runs the commands and returns nothing + """ + cmd = ['git'] + if self.quiet: + cmd.append('--quiet') + cmd.extend(['rm', '-rf', '.']) + self._run_command(cmd, cwd=self.path) + + fd = open(os.path.join(self.path, 'dead.package'), 'w') + fd.write(message + '\n') + fd.close() + + cmd = ['git', 'add', os.path.join(self.path, 'dead.package')] + self._run_command(cmd, cwd=self.path) + + self.commit(message=message) + + def update(self, bodhi_config, template='bodhi.template', bugs=[]): + """Submit an update to bodhi using the provided template.""" + + # build up the bodhi arguments, based on which version of bodhi is + # installed + bodhi_major_version = _get_bodhi_version()[0] + if bodhi_major_version < 2: + cmd = ['bodhi', '--bodhi-url', bodhi_config['url'], + '--new', '--release', self.branch_merge, + '--file', 'bodhi.template', self.nvr, '--username', + self.user] + elif bodhi_major_version == 2: + cmd = ['bodhi', '--bodhi-url', bodhi_config['url'], + 'updates', 'new', '--file', 'bodhi.template', + '--user', self.user, self.nvr] + else: + msg = 'This system has bodhi v{0}, which is unsupported.' + msg = msg.format(bodhi_major_version) + raise Exception(msg) + self._run_command(cmd, shell=True) + + def load_kojisession(self, anon=False): + try: + return super(Commands, self).load_kojisession(anon) + except pyrpkg.rpkgAuthError: + self.log.info("You might want to run fedora-packager-setup to " + "regenerate SSL certificate. For more info see " + "https://fedoraproject.org/wiki/Using_the_Koji_build" + "_system#Fedora_Account_System_.28FAS2.29_Setup") + raise + + +def _get_bodhi_version(): + """ + Use bodhi --version to determine the version of the Bodhi CLI that's + installed on the system, then return a list of the version components. + For example, if bodhi --version returns "2.1.9", this function will return + [2, 1, 9]. + """ + bodhi = subprocess.Popen(['bodhi', '--version'], stdout=subprocess.PIPE) + version = bodhi.communicate()[0].strip() + return [int(component) for component in version.split('.')] + + +if __name__ == "__main__": + from fedpkg.__main__ import main + main() diff --git a/fedpkg/__main__.py b/fedpkg/__main__.py new file mode 100644 index 0000000..e46c418 --- /dev/null +++ b/fedpkg/__main__.py @@ -0,0 +1,89 @@ +#!/usr/bin/python +# fedpkg - a script to interact with the Fedora Packaging system +# +# Copyright (C) 2011 Red Hat Inc. +# Author(s): Jesse Keating +# +# 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. See http://www.gnu.org/copyleft/gpl.html for +# the full text of the license. + +import argparse +import logging +import os +import sys + +import fedpkg +import pyrpkg +import pyrpkg.utils + +import six +if six.PY3: # SafeConfigParser == ConfigParser, former deprecated in >= 3.2 + from six.moves.configparser import ConfigParser +else: + from six.moves.configparser import SafeConfigParser as ConfigParser + + +cli_name = os.path.basename(sys.argv[0]) + + +def main(): + # Setup an argparser and parse the known commands to get the config file + parser = argparse.ArgumentParser(add_help=False) + parser.add_argument('-C', '--config', help='Specify a config file to use', + default='/etc/rpkg/%s.conf' % cli_name) + + (args, other) = parser.parse_known_args() + + # Make sure we have a sane config file + if not os.path.exists(args.config) and \ + not other[-1] in ['--help', '-h', 'help']: + sys.stderr.write('Invalid config file %s\n' % args.config) + sys.exit(1) + + # Setup a configuration object and read config file data + config = ConfigParser() + config.read(args.config) + + client = fedpkg.cli.fedpkgClient(config, name=cli_name) + client.do_imports(site='fedpkg') + client.parse_cmdline() + + if not client.args.path: + try: + client.args.path = pyrpkg.utils.getcwd() + except: + print('Could not get current path, have you deleted it?') + sys.exit(1) + + # setup the logger -- This logger will take things of INFO or DEBUG and + # log it to stdout. Anything above that (WARN, ERROR, CRITICAL) will go + # to stderr. Normal operation will show anything INFO and above. + # Quiet hides INFO, while Verbose exposes DEBUG. In all cases WARN or + # higher are exposed (via stderr). + log = pyrpkg.log + client.setupLogging(log) + + if client.args.v: + log.setLevel(logging.DEBUG) + elif client.args.q: + log.setLevel(logging.WARNING) + else: + log.setLevel(logging.INFO) + + # Run the necessary command + try: + sys.exit(client.args.command()) + except KeyboardInterrupt: + pass + except Exception as e: + log.error('Could not execute %s: %s' % + (client.args.command.__name__, e)) + if client.args.v: + raise + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/fedpkg/cli.py b/fedpkg/cli.py new file mode 100644 index 0000000..7c57d8f --- /dev/null +++ b/fedpkg/cli.py @@ -0,0 +1,210 @@ +# cli.py - a cli client class module for fedpkg +# +# Copyright (C) 2011 Red Hat Inc. +# Author(s): Jesse Keating +# +# 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. See http://www.gnu.org/copyleft/gpl.html for +# the full text of the license. + +from pyrpkg.cli import cliClient +import sys +import os +import logging +import re +import textwrap +import hashlib + +import pkgdb2client + + +class fedpkgClient(cliClient): + def __init__(self, config, name=None): + self.DEFAULT_CLI_NAME = 'fedpkg' + super(fedpkgClient, self).__init__(config, name) + self.setup_fed_subparsers() + + def setup_fed_subparsers(self): + """Register the fedora specific targets""" + + self.register_retire() + self.register_update() + + # Target registry goes here + def register_retire(self): + """Register the retire target""" + + retire_parser = self.subparsers.add_parser( + 'retire', + help='Retire a package', + description='This command will remove all files from the repo, ' + 'leave a dead.package file, push the changes and ' + 'retire the package in pkgdb.' + ) + retire_parser.add_argument('reason', + help='Reason for retiring the package') + retire_parser.set_defaults(command=self.retire) + + def register_update(self): + update_parser = self.subparsers.add_parser( + 'update', + help='Submit last build as update', + description='This will create a bodhi update request for the ' + 'current package n-v-r.' + ) + update_parser.set_defaults(command=self.update) + + # Target functions go here + def retire(self): + try: + module_name = self.cmd.module_name + ns_module_name = self.cmd.ns_module_name + namespace = ns_module_name.split(module_name)[0].rstrip('/') + # Skip if package is already retired to allow to retire only in + # pkgdb + if os.path.isfile(os.path.join(self.cmd.path, 'dead.package')): + self.log.warn('dead.package found, package probably already ' + 'retired - will not remove files from git or ' + 'overwrite existing dead.package file') + else: + self.cmd.retire(self.args.reason) + self.push() + + pkgdb_config = dict(self.config.items('%s.pkgdb' % self.name)) + branch = self.cmd.branch_merge + pkgdb = pkgdb2client.PkgDB(url=pkgdb_config['url'], + login_callback=pkgdb2client.ask_password) + pkgdb.retire_packages(module_name, branch, namespace=namespace) + except Exception as e: + self.log.error('Could not retire package: %s' % e) + sys.exit(1) + + def _format_update_clog(self, clog): + ''' Format clog for the update template. ''' + lines = [l for l in clog.split('\n') if l] + if len(lines) == 0: + return "- Rebuilt.", "" + elif len(lines) == 1: + return lines[0], "" + log = ["# Changelog:"] + log.append('# - ' + lines[0]) + for l in lines[1:]: + log.append('# ' + l) + log.append('#') + return lines[0], "\n".join(log) + + def update(self): + template = """\ +[ %(nvr)s ] + +# bugfix, security, enhancement, newpackage (required) +type= + +# testing, stable +request=testing + +# Bug numbers: 1234,9876 +bugs=%(bugs)s + +%(changelog)s +# Here is where you give an explanation of your update. +notes=%(descr)s + +# Enable request automation based on the stable/unstable karma thresholds +autokarma=True +stable_karma=3 +unstable_karma=-3 + +# Automatically close bugs when this marked as stable +close_bugs=True + +# Suggest that users restart after update +suggest_reboot=False +""" + + bodhi_args = {'nvr': self.cmd.nvr, + 'bugs': '', + 'descr': 'Here is where you give an explanation' + ' of your update.'} + + # Extract bug numbers from the latest changelog entry + self.cmd.clog() + clog = file('clog').read() + bugs = re.findall(r'#([0-9]*)', clog) + if bugs: + bodhi_args['bugs'] = ','.join(bugs) + + # Use clog as default message + bodhi_args['descr'], bodhi_args['changelog'] = \ + self._format_update_clog(clog) + + template = textwrap.dedent(template) % bodhi_args + + # Calculate the hash of the unaltered template + orig_hash = hashlib.new('sha1') + orig_hash.update(template) + orig_hash = orig_hash.hexdigest() + + # Write out the template + out = file('bodhi.template', 'w') + out.write(template) + out.close() + + # Open the template in a text editor + editor = os.getenv('EDITOR', 'vi') + self.cmd._run_command([editor, 'bodhi.template'], shell=True) + + # Check to see if we got a template written out. Bail otherwise + if not os.path.isfile('bodhi.template'): + self.log.error('No bodhi update details saved!') + sys.exit(1) + # If the template was changed, submit it to bodhi + hash = self.cmd.lookasidecache.hash_file('bodhi.template', 'sha1') + if hash != orig_hash: + try: + bodhi_config = dict(self.config.items('%s.bodhi' % self.name)) + self.cmd.update(bodhi_config, template='bodhi.template') + except Exception as e: + self.log.error('Could not generate update request: %s' % e) + sys.exit(1) + else: + self.log.info('Bodhi update aborted!') + + # Clean up + os.unlink('bodhi.template') + os.unlink('clog') + +if __name__ == '__main__': + client = cliClient() + client._do_imports() + client.parse_cmdline() + + if not client.args.path: + try: + client.args.path = os.getcwd() + except: + print('Could not get current path, have you deleted it?') + sys.exit(1) + + # setup the logger -- This logger will take things of INFO or DEBUG and + # log it to stdout. Anything above that (WARN, ERROR, CRITICAL) will go + # to stderr. Normal operation will show anything INFO and above. + # Quiet hides INFO, while Verbose exposes DEBUG. In all cases WARN or + # higher are exposed (via stderr). + log = client.site.log + client.setupLogging(log) + + if client.args.v: + log.setLevel(logging.DEBUG) + elif client.args.q: + log.setLevel(logging.WARNING) + else: + log.setLevel(logging.INFO) + + # Run the necessary command + try: + client.args.command() + except KeyboardInterrupt: + pass diff --git a/fedpkg/lookaside.py b/fedpkg/lookaside.py new file mode 100644 index 0000000..c679151 --- /dev/null +++ b/fedpkg/lookaside.py @@ -0,0 +1,28 @@ +# Copyright (c) 2015 - Red Hat Inc. +# +# 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. See http://www.gnu.org/copyleft/gpl.html for +# the full text of the license. + + +"""Interact with the Fedora lookaside cache + +We need to override the pyrpkg.lookasidecache module to handle our custom +download path. +""" + + +from pyrpkg.lookaside import CGILookasideCache + + +class FedoraLookasideCache(CGILookasideCache): + def __init__(self, hashtype, download_url, upload_url, + client_cert=None, ca_cert=None): + super(FedoraLookasideCache, self).__init__( + hashtype, download_url, upload_url, client_cert=client_cert, + ca_cert=ca_cert) + + self.download_path = ( + '%(name)s/%(filename)s/%(hashtype)s/%(hash)s/%(filename)s') diff --git a/setup.cfg b/setup.cfg index e3c9d67..8d7d454 100644 --- a/setup.cfg +++ b/setup.cfg @@ -10,7 +10,6 @@ detailed-errors = 1 with-coverage = 1 cover-package = fedpkg cover-erase = 1 -tests=../test/ [flake8] -max-line-length = 100 \ No newline at end of file +max-line-length = 100 diff --git a/setup.py b/setup.py index 8772714..2afcf6e 100755 --- a/setup.py +++ b/setup.py @@ -1,5 +1,6 @@ #!/usr/bin/python -from setuptools import setup +from setuptools import setup, find_packages + try: from subprocess import getstatusoutput except: @@ -20,15 +21,15 @@ setup( "package sources in a git repository"), license="GPLv2+", url="http://fedorahosted.org/fedpkg", - package_dir={'': 'src'}, - packages=['fedpkg'], + packages=find_packages(), scripts=[ - 'src/bin/fedpkg', - 'src/bin/fedpkg-stage', + 'bin/fedpkg', + 'bin/fedpkg-stage', ], - data_files=[(bash_completion_dir(), ['src/fedpkg.bash']), - ('/etc/rpkg', ['src/fedpkg.conf']), - ('/usr/share/zsh/site-functions', ['src/_fedpkg']), + data_files=[(bash_completion_dir(), ['conf/bash-completion/fedpkg.bash']), + ('/etc/rpkg', ['conf/etc/rpkg/fedpkg.conf', + 'conf/etc/rpkg/fedpkg-stage.conf']), + ('/usr/share/zsh/site-functions', ['conf/zsh-completion/_fedpkg']), ], tests_require=['nose', 'mock'], diff --git a/src/_fedpkg b/src/_fedpkg deleted file mode 100644 index ac24300..0000000 --- a/src/_fedpkg +++ /dev/null @@ -1,441 +0,0 @@ -#compdef fedpkg - -(( $+functions[_fedpkg_targets] )) || -_fedpkg_targets() -{ - local expl - - _wanted koji-targets expl 'target' compadd \ - ${${(f)"$(_call_program koji-targets koji list-targets --quiet 2>/dev/null)"}%% *} -} - -(( $+functions[_fedpkg_arches] )) || -_fedpkg_arches() -{ - local expl - local -a arches - - arches=( /etc/mock/[^-]##-[^-]##-[^-]##.cfg ) - _wanted mock-arches expl 'arch' compadd \ - ${(u)${arches#/etc/mock/[^-]##-[^-]##-}%.cfg} -} - -(( $+functions[_fedpkg_packages] )) || -_fedpkg_packages() -{ - local expl - - _wanted repo-packages expl 'package' compadd \ - ${${(fu)"$(repoquery -Cs -- "$words[CURRENT]*")"}%-[^-]##-[^-]##.src.rpm} -} - -(( $+functions[_fedpkg_branches] )) || -_fedpkg_branches() -{ - local expl - local -a git_opts - local -a branches - - (( ${words[(I)--path]} )) && - git_opts=( --git-dir ${words[${words[(i)--path]}+1]} ) - - branches=(${${(f)"$(git $git_opts for-each-ref --format='%(refname)' refs/heads 2>/dev/null)"}#refs/heads/}) - branches+=(${${(f)"$(git $git_opts for-each-ref --format='%(refname)' refs/remotes 2>/dev/null)"}##refs/remotes/*/}) - - _wanted branch-names expl 'branch-name' compadd \ - ${(u)branches} -} - -(( $+functions[_fedpkg-help] )) || -_fedpkg-help () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' -} - -(( $+functions[_fedpkg-build] )) || -_fedpkg-build () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '--arches[build for specific arches]:*:arch:_fedpkg_arches' \ - '--md5[use md5 checksums]' \ - '--nowait[don'\''t wait on build]' \ - '--target[define build target to build into]:target:_fedpkg_targets' \ - '--background[run the build at a low priority]' \ - '--skip-tag[do not attempt to tag package]' \ - '--scratch[perform a scratch build]' \ - '--srpm[build from an srpm]::srpm:_files -g "*.src.rpm"' -} - -(( $+functions[_fedpkg-chain-build] )) || -_fedpkg-chain-build () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '--arches[build for specific arches]:*:arch:_fedpkg_arches' \ - '--md5[use md5 checksums]' \ - '--nowait[on'\''t wait on build]' \ - '--target[define build target to build into]:target:_fedpkg_targets' \ - '--background[run the build at a low priority]' \ - '*:package:_fedpkg_packages' -} - -(( $+functions[_fedpkg-clean] )) || -_fedpkg-clean () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '(-n --dry-run)'{-n,--dry-run}'[perform a dry-run]' \ - '-x[do not follow .gitignore rules]' -} - -(( $+functions[_fedpkg-clog] )) || -_fedpkg-clog () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '--raw[generate a more "raw" clog without twiddling the contents]' -} - -(( $+functions[_fedpkg-clone] )) || -_fedpkg-clone () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '(-B --branches)'{-B,--branches}'[do an old style checkout with subdirs for branches]' \ - '(-b --branch)'{-b,--branch}'[check out a specific branch]:branch:_fedpkg_branches' \ - '(-a --anonymous)'{-a,--anonymous}'[check out a module anonymously]' \ - ':package:_fedpkg_packages' -} - -(( $+functions[_fedpkg-commit] )) || -_fedpkg-commit () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '(-c --clog)'{-c,--clog}'[generate the commit message from the %changelog section]' \ - '--raw[make the clog raw]' \ - '(-t --tag)'{-t,--tag}'[create a tag for this commit]' \ - '(-m --message)'{-m,--message}'[use the given commit message]:message' \ - '(-F --file)'{-F,--file}'[take the commit message from the given file]:file:_files' \ - '(-p --push)'{-p,--push}'[commit and push as one action]' \ - '*:file:_files' -} - -(( $+functions[_fedpkg-compile] )) || -_fedpkg-compile () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '--builddir[define an alternate builddir]:builddir:_files -/' \ - '--arch[prep for a specific arch]:arch:_fedpkg_arches' \ - '--short-circuit[short-circuit compile]' -} - -(( $+functions[_fedpkg-copr-build] )) || -_fedpkg-copr-build () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '--nowait[on'\''t wait on build]' \ - '*:project' -} - -(( $+functions[_fedpkg-diff] )) || -_fedpkg-diff () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '--cached[view staged changes]' \ - '*:file:_files' -} - -(( $+functions[_fedpkg-gimmespec] )) || -_fedpkg-gimmespec () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' -} - -(( $+functions[_fedpkg-gitbuildhash] )) || -_fedpkg-gitbuildhash () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - ':build' -} - -(( $+functions[_fedpkg-giturl] )) || -_fedpkg-giturl () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' -} - -(( $+functions[_fedpkg-import] )) || -_fedpkg-import () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - ':srpm:_files -g "*.src.rpm"' -} - -(( $+functions[_fedpkg-install] )) || -_fedpkg-install () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '--builddir[define an alternate builddir]:builddir:_files -/' \ - '--arch[prep for a specific arch]:arch:_fedpkg_arches' \ - '--short-circuit[short-circuit compile]' -} - -(( $+functions[_fedpkg-lint] )) || -_fedpkg-lint () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '(-i --info)'{-i,--info}'[display explanations for reported messages]' \ - '(-r --rpmlintconf)'{-r,--rpmlintconf}'[use a specific configuration file for rpmlint]:rpmlintconf:_files' -} - -(( $+functions[_fedpkg-local] )) || -_fedpkg-local () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '--builddir[define an alternate builddir]:builddir:_files -/' \ - '--arch[prep for a specific arch]:arch:_fedpkg_arches' \ - '--md5[use md5 checksums]' -} - -(( $+functions[_fedpkg-mockbuild] )) || -_fedpkg-mockbuild () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '--root[override mock root]:root:_files -/' \ - '--md5[use md5 checksums]' -} - -(( $+functions[_fedpkg-mock-config] )) || -_fedpkg-mock-config () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '--target[override target used for config]:target:_fedpkg_targets' - '--arch[override local arch]:arch:_fedpkg_arches' -} - -(( $+functions[_fedpkg-new] )) || -_fedpkg-new () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' -} - -(( $+functions[_fedpkg-new-sources] )) || -_fedpkg-new-sources () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '*:file:_files' -} - -(( $+functions[_fedpkg-patch] )) || -_fedpkg-patch () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '--rediff[recreate gendiff file retaining comments]' \ - ':suffix' -} - -(( $+functions[_fedpkg-prep] )) || -_fedpkg-prep () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '--builddir[define an alternate builddir]:builddir:_files -/' \ - '--arch[prep for a specific arch]:arch:_fedpkg_arches' -} - -(( $+functions[_fedpkg-pull] )) || -_fedpkg-pull () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '(--no-rebase)--rebase[rebase the locally committed changes on top of the remote changes]' \ - '(--rebase)--no-rebase[do not rebase, override .git settings to automatically rebase]' -} - -(( $+functions[_fedpkg-push] )) || -_fedpkg-push () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' -} - -(( $+functions[_fedpkg-scratch-build] )) || -_fedpkg-scratch-build () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '--arches[build for specific arches]:*:arch:_fedpkg_arches' \ - '--md5[use md5 checksums]' \ - '--nowait[on'\''t wait on build]' \ - '--target[define build target to build into]:target:_fedpkg_targets' \ - '--background[run the build at a low priority]' \ - '--srpm[build from an srpm]::srpm:_files -g "*.src.rpm"' -} - -(( $+functions[_fedpkg-sources] )) || -_fedpkg-sources () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '--outdir[directory to download files into]:outdir:_files -/' -} - -(( $+functions[_fedpkg-srpm] )) || -_fedpkg-srpm () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '--md5[use md5 checksums]' -} - -(( $+functions[_fedpkg-switch-branch] )) || -_fedpkg-switch-branch () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '(: -l --list)'{-l,--list}'[list both remote-tracking branches and local branches]' \ - '(-):branch:_fedpkg_branches' -} - -(( $+functions[_fedpkg-tag] )) || -_fedpkg-tag () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '(-f --force)'{-f,--force}'[force the creation of the tag]' \ - '(-m --message)'{-m,--message}'[use the given commit message]:message' \ - '(-c --clog)'{-c,--clog}'[generate the commit message from the %changelog section]' \ - '--raw[make the clog raw]' \ - '(-F --file)'{-F,--file}'[take the commit message from the given file]:file:_files' \ - '(-l --list)'{-l,--list}'[list all tags with a given pattern]' \ - '(-d --delete)'{-d,--delete}'[delete a tag]' \ - ':tag' -} - -(( $+functions[_fedpkg-unused-patches] )) || -_fedpkg-unused-patches () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' -} - -(( $+functions[_fedpkg-upload] )) || -_fedpkg-upload () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '*:file:_files' -} - -(( $+functions[_fedpkg-verify-files] )) || -_fedpkg-verify-files () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '--builddir[define an alternate builddir]:builddir:_files -/' \ - '--arch[prep for a specific arch]:arch:_fedpkg_arches' -} - -(( $+functions[_fedpkg-verrel] )) || -_fedpkg-verrel () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' -} - -(( $+functions[_fedpkg-retire] )) || -_fedpkg-retire () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' \ - '(-p --push)'{-p,--push}'[push changes to remote repository]' \ - ':message' -} - -(( $+functions[_fedpkg-update] )) || -_fedpkg-update () { - _arguments -C \ - '(-h --help)'{-h,--help}'[show help message and exit]' -} - -(( $+functions[_fedpkg_commands] )) || -_fedpkg_commands () { - local -a fedpkg_commands - fedpkg_commands=( - help:'show usage' - build:'request build' - chain-build:'build current package in order with other packages' - clean:'remove untracked files' - clog:'make a clog file containing top changelog entry' - clone:'clone and checkout a module' - commit:'commit changes' - compile:'local test rpmbuild compile' - copr-build:'build package in Copr' - diff:'show changes between commits, commit and working tree, etc' - gimmespec:'print the spec file name' - gitbuildhash:'print the git hash used to build the provided n-v-r' - giturl:'print the git url for building' - import:'import srpm content into a module' - install:'local test rpmbuild install' - lint:'run rpmlint against local spec and build output if present' - local:'local test rpmbuild binary' - mockbuild:'local test build using mock' - mock-config:'generate a mock config' - new:'diff against last tag' - new-sources:'upload new source files' - patch:'create and add a gendiff patch file' - prep:'local test rpmbuild prep' - pull:'pull changes from remote repository and update working copy' - push:'push changes to remote repository' - scratch-build:'request scratch build' - sources:'download source files' - srpm:'create a source rpm' - switch-branch:'work with branches' - tag:'management of git tags' - unused-patches:'print list of patches not referenced by name in the specfile' - upload:'upload source files' - verify-files:'locally verify %files section' - verrel:'print the name-version-release' - retire:'retire a package' - update:'submit last build as an update' - ) - - integer ret=1 - - # TODO: Is this the correct way of doing it? Should we be using _alternative - # and separate functions for each set of commands instead? - _describe -t fedpkg-commands 'fedpkg command' fedpkg_commands && ret=0 - - return ret -} - -_fedpkg() { - local -A fedpkg_aliases - fedpkg_aliases=( - co clone - ci commit - ) - integer ret=1 - - local curcontext=$curcontext state line - declare -A opt_args - - _arguments -C \ - '(- :)'{-h,--help}'[show help message and exit]' \ - '(-C --config)'{-C,--config}'[specify a config file to use]:config file:_files' \ - '--dist[override the discovered distribution]:distribution' \ - '--user[override the discovered user name]:user' \ - '--path[define the directory to work in (defaults to cwd)]:working direcory:_directories' \ - '(-q)-v[run with verbose debug output]' \ - '(-v)-q[run quietly only displaying errors]' \ - '(-): :->command' \ - '(-)*:: :->option-or-argument' && return - - case $state in - (command) - _fedpkg_commands && ret=0 - ;; - (option-or-argument) - local cmd=$words[1] - (( $+fedpkg_aliases[$cmd] )) && - cmd=$fedpkg_aliases[$cmd] - - curcontext=${curcontext%:*:*}:fedpkg-$cmd: - - if (( $+functions[_fedpkg-$cmd] )); then - _call_function ret _fedpkg-$cmd - elif zstyle -T :completion:$curcontext: use-fallback; then - _files && ret=0 - else - _message 'unknown sub-command' - fi - ;; - esac - - return ret -} - -_fedpkg diff --git a/src/bin/fedpkg b/src/bin/fedpkg deleted file mode 100755 index bc2846d..0000000 --- a/src/bin/fedpkg +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/python -# fedpkg - a script to interact with the Fedora Packaging system -# -# Copyright (C) 2011 Red Hat Inc. -# Author(s): Jesse Keating -# -# 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. See http://www.gnu.org/copyleft/gpl.html for -# the full text of the license. - -from fedpkg.__main__ import main - -if __name__ == "__main__": - main() diff --git a/src/bin/fedpkg-stage b/src/bin/fedpkg-stage deleted file mode 100644 index b7bdb34..0000000 --- a/src/bin/fedpkg-stage +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/python -# fedpkg-stage - a script to interact with the Fedora Packaging system -# -# Copyright (C) 2016 Red Hat Inc. -# Author(s): Chenxiong Qi -# -# 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. See http://www.gnu.org/copyleft/gpl.html for -# the full text of the license. - -from fedpkg.__main__ import main - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/src/fedpkg-stage.conf b/src/fedpkg-stage.conf deleted file mode 100644 index f192895..0000000 --- a/src/fedpkg-stage.conf +++ /dev/null @@ -1,24 +0,0 @@ -[fedpkg-stage] -lookaside = http://pkgs.stg.fedoraproject.org/repo/pkgs -lookasidehash = md5 -lookaside_cgi = https://pkgs.stg.fedoraproject.org/repo/pkgs/upload.cgi -gitbaseurl = ssh://%(user)s@pkgs.stg.fedoraproject.org/%(module)s -anongiturl = git://pkgs.stg.fedoraproject.org/%(module)s -tracbaseurl = https://%(user)s:%(password)s@fedorahosted.org/rel-eng/login/xmlrpc -branchre = f\d$|f\d\d$|el\d$|olpc\d$|master$ -kojiconfig = /etc/koji/stg-config -build_client = koji -clone_config = - bz.default-tracker partner-bugzilla.redhat.com - bz.default-product Fedora - bz.default-version rawhide - bz.default-component %(module)s - sendemail.to %(module)s-owner@fedoraproject.org - push.default simple -distgit_namespaced = True - -[fedpkg-stage.bodhi] -url = https://bodhi.stg.fedoraproject.org/ - -[fedpkg-stage.pkgdb] -url = https://admin.stg.fedoraproject.org/pkgdb/ \ No newline at end of file diff --git a/src/fedpkg.bash b/src/fedpkg.bash deleted file mode 100644 index a7ae59e..0000000 --- a/src/fedpkg.bash +++ /dev/null @@ -1,322 +0,0 @@ -# fedpkg bash completion - -_fedpkg() -{ - COMPREPLY=() - - in_array() - { - local i - for i in $2; do - [[ $i = $1 ]] && return 0 - done - return 1 - } - - _filedir_exclude_paths() - { - _filedir "$@" - for ((i=0; i<=${#COMPREPLY[@]}; i++)); do - [[ ${COMPREPLY[$i]} =~ /?\.git/? ]] && unset COMPREPLY[$i] - done - } - - local cur prev - # _get_comp_words_by_ref is in bash-completion >= 1.2, which EL-5 lacks. - if type _get_comp_words_by_ref &>/dev/null; then - _get_comp_words_by_ref cur prev - else - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" - fi - - # global options - - local options="--help -v -q" - local options_value="--dist --user --path" - local commands="build chain-build ci clean clog clone co commit compile \ - container-build diff gimmespec giturl help gitbuildhash import install lint \ - local mockbuild mock-config new new-sources patch prep pull push retire \ - scratch-build sources srpm switch-branch tag unused-patches update upload \ - verify-files verrel" - - # parse main options and get command - - local command= - local command_first= - local path= - - local i w - for (( i = 0; i < ${#COMP_WORDS[*]} - 1; i++ )); do - w="${COMP_WORDS[$i]}" - # option - if [[ ${w:0:1} = - ]]; then - if in_array "$w" "$options_value"; then - ((i++)) - [[ "$w" = --path ]] && path="${COMP_WORDS[$i]}" - fi - # command - elif in_array "$w" "$commands"; then - command="$w" - command_first=$((i+1)) - break - fi - done - - # complete base options - - if [[ -z $command ]]; then - if [[ $cur == -* ]]; then - COMPREPLY=( $(compgen -W "$options $options_value" -- "$cur") ) - return 0 - fi - - case "$prev" in - --dist) - ;; - --user|-u) - ;; - --path) - _filedir_exclude_paths - ;; - *) - COMPREPLY=( $(compgen -W "$commands" -- "$cur") ) - ;; - esac - - return 0 - fi - - # parse command specific options - - local options= - local options_target= options_arches= options_branch= options_string= options_file= options_dir= options_srpm= options_mroot= options_builder= - local after= after_more= - - case $command in - help|gimmespec|gitbuildhash|giturl|lint|new|push|unused-patches|update|verrel) - ;; - build) - options="--nowait --background --skip-tag --scratch" - options_srpm="--srpm" - options_target="--target" - ;; - chain-build) - options="--nowait --background" - options_target="--target" - after="package" - after_more=true - ;; - clean) - options="--dry-run -x" - ;; - clog) - options="--raw" - ;; - clone|co) - options="--branches --anonymous" - options_branch="-b" - after="package" - ;; - commit|ci) - options="--push --clog --raw --tag" - options_string="--message" - options_file="--file" - after="file" - after_more=true - ;; - compile|install) - options="--short-circuit" - options_arch="--arch" - options_dir="--builddir" - ;; - container-build) - options="--scratch" - options_target="--target" - options_builder="--build-with" - ;; - diff) - options="--cached" - after="file" - after_more=true - ;; - import) - options="--create" - options_branch="--branch" - after="srpm" - ;; - lint) - options="--info" - ;; - local) - options="--md5" - options_arch="--arch" - options_dir="--builddir" - ;; - mock-config) - options="--target" - options_arch="--arch" - ;; - mockbuild) - options="--md5 --no-clean --no-cleanup-after --no-clean-all" - options_mroot="--root" - ;; - patch) - options="--rediff" - options_string="--suffix" - ;; - prep|verify-files) - options_arch="--arch" - options_dir="--builddir" - ;; - pull) - options="--rebase --no-rebase" - ;; - retire) - after_more=true - ;; - scratch-build) - options="--nowait --background" - options_target="--target" - options_arches="--arches" - options_srpm="--srpm" - ;; - sources) - options_dir="--outdir" - ;; - srpm) - options="--md5" - ;; - switch-branch) - options="--list" - after="branch" - ;; - tag) - options="--clog --raw --force --list --delete" - options_string="--message" - options_file="--file" - after_more=true - ;; - upload|new-sources) - after="file" - after_more=true - ;; - esac - - local all_options="--help $options" - local all_options_value="$options_target $options_arches $options_branch $options_string $options_file $options_dir $options_srpm $options_mroot $options_builder" - - # count non-option parameters - - local i w - local last_option= - local after_counter=0 - for (( i = $command_first; i < ${#COMP_WORDS[*]} - 1; i++)); do - w="${COMP_WORDS[$i]}" - if [[ ${w:0:1} = - ]]; then - if in_array "$w" "$all_options"; then - last_option="$w" - continue - elif in_array "$w" "$all_options_value"; then - last_option="$w" - ((i++)) - continue - fi - fi - in_array "$last_option" "$options_arches" || ((after_counter++)) - done - - # completion - - if [[ -n $options_target ]] && in_array "$prev" "$options_target"; then - COMPREPLY=( $(compgen -W "$(_fedpkg_target)" -- "$cur") ) - - elif [[ -n $options_arches ]] && in_array "$last_option" "$options_arches"; then - COMPREPLY=( $(compgen -W "$(_fedpkg_arch) $all_options" -- "$cur") ) - - elif [[ -n $options_builder ]] && in_array "$prev" "$options_builder"; then - COMPREPLY=( $(compgen -W "$(_fedpkg_builder)" -- "$cur") ) - - elif [[ -n $options_srpm ]] && in_array "$prev" "$options_srpm"; then - _filedir_exclude_paths "*.src.rpm" - - elif [[ -n $options_branch ]] && in_array "$prev" "$options_branch"; then - COMPREPLY=( $(compgen -W "$(_fedpkg_branch "$path")" -- "$cur") ) - - elif [[ -n $options_file ]] && in_array "$prev" "$options_file"; then - _filedir_exclude_paths - - elif [[ -n $options_dir ]] && in_array "$prev" "$options_dir"; then - _filedir_exclude_paths -d - - elif [[ -n $options_string ]] && in_array "$prev" "$options_string"; then - COMPREPLY=( ) - - elif [[ -n $options_mroot ]] && in_array "$prev" "$options_mroot"; then - COMPREPLY=( ) - if declare -F _mock_root &>/dev/null; then - _mock_root - elif declare -F _xfunc &>/dev/null; then - _xfunc mock _mock_root - fi - - else - local after_options= - - if [[ $after_counter -eq 0 ]] || [[ $after_more = true ]]; then - case $after in - file) _filedir_exclude_paths ;; - srpm) _filedir_exclude_paths "*.src.rpm" ;; - branch) after_options="$(_fedpkg_branch "$path")" ;; - package) after_options="$(_fedpkg_package "$cur")";; - esac - fi - - if [[ $cur != -* ]]; then - all_options= - all_options_value= - fi - - COMPREPLY+=( $(compgen -W "$all_options $all_options_value $after_options" -- "$cur" ) ) - fi - - return 0 -} && -complete -F _fedpkg fedpkg - -_fedpkg_target() -{ - koji list-targets --quiet 2>/dev/null | cut -d" " -f1 -} - -_fedpkg_arch() -{ - echo "i386 i686 x86_64 armv5tel armv7hl armv7hnl ppc ppc64 ppc64p7 s390 s390x" -} - -_fedpkg_builder() -{ - echo "koji osbs" -} - -_fedpkg_branch() -{ - local git_options= format="--format %(refname:short)" - [[ -n $1 ]] && git_options="--git-dir=$1/.git" - - git $git_options for-each-ref $format 'refs/remotes' | sed 's,.*/,,' - git $git_options for-each-ref $format 'refs/heads' -} - -_fedpkg_package() -{ - repoquery -C --qf=%{sourcerpm} "$1*" 2>/dev/null | sort -u | sed -r 's/(-[^-]*){2}\.src\.rpm$//' -} - -# Local variables: -# mode: shell-script -# sh-basic-offset: 4 -# sh-indent-comment: t -# indent-tabs-mode: nil -# End: -# ex: ts=4 sw=4 et filetype=sh diff --git a/src/fedpkg.conf b/src/fedpkg.conf deleted file mode 100644 index b0d132c..0000000 --- a/src/fedpkg.conf +++ /dev/null @@ -1,24 +0,0 @@ -[fedpkg] -lookaside = http://pkgs.fedoraproject.org/repo/pkgs -lookasidehash = md5 -lookaside_cgi = https://pkgs.fedoraproject.org/repo/pkgs/upload.cgi -gitbaseurl = ssh://%(user)s@pkgs.fedoraproject.org/%(module)s -anongiturl = git://pkgs.fedoraproject.org/%(module)s -tracbaseurl = https://%(user)s:%(password)s@fedorahosted.org/rel-eng/login/xmlrpc -branchre = f\d$|f\d\d$|el\d$|olpc\d$|master$ -kojiconfig = /etc/koji.conf -build_client = koji -clone_config = - bz.default-tracker bugzilla.redhat.com - bz.default-product Fedora - bz.default-version rawhide - bz.default-component %(module)s - sendemail.to %(module)s-owner@fedoraproject.org - push.default simple -distgit_namespaced = True - -[fedpkg.bodhi] -url = https://bodhi.fedoraproject.org/ - -[fedpkg.pkgdb] -url = https://admin.fedoraproject.org/pkgdb/ \ No newline at end of file diff --git a/src/fedpkg/__init__.py b/src/fedpkg/__init__.py deleted file mode 100644 index 0fae271..0000000 --- a/src/fedpkg/__init__.py +++ /dev/null @@ -1,351 +0,0 @@ -# fedpkg - a Python library for RPM Packagers -# -# Copyright (C) 2011 Red Hat Inc. -# Author(s): Jesse Keating -# -# 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. See http://www.gnu.org/copyleft/gpl.html for -# the full text of the license. - -import pyrpkg -import os -import git -import re -import fedora_cert -import platform -import subprocess - -from . import cli # noqa -from .lookaside import FedoraLookasideCache -from pyrpkg.utils import cached_property - - -class Commands(pyrpkg.Commands): - - def __init__(self, path, lookaside, lookasidehash, lookaside_cgi, - gitbaseurl, anongiturl, branchre, kojiconfig, - build_client, user=None, dist=None, target=None, - quiet=False, distgit_namespaced=False): - """Init the object and some configuration details.""" - - # We are subclassing to set kojiconfig to none, so that we can - # make it a property to potentially use a secondary config - super(Commands, self).__init__(path, lookaside, lookasidehash, - lookaside_cgi, gitbaseurl, anongiturl, - branchre, kojiconfig, build_client, - user=user, dist=dist, target=target, - quiet=quiet, - distgit_namespaced=distgit_namespaced) - - # New data - self.secondary_arch = { - 'ppc': [ - 'apmud', - 'libbsr', - 'librtas', - 'libservicelog', - 'libvpd', - 'lsvpd', - 'powerpc-utils', - 'powerpc-utils-papr', - 'powerpc-utils-python', - 'ppc64-diag', - 'ppc64-utils', - 'servicelog', - 'yaboot', - ], - 'arm': ['xorg-x11-drv-omapfb'], - 's390': ['s390utils', 'openssl-ibmca', 'libica', 'libzfcphbaapi'], - } - - # New properties - self._kojiconfig = None - # Store this for later - self._orig_kojiconfig = kojiconfig - - # Add new properties - @property - def kojiconfig(self): - """This property ensures the kojiconfig attribute""" - - if not self._kojiconfig: - self.load_kojiconfig() - return self._kojiconfig - - @kojiconfig.setter - def kojiconfig(self, value): - self._kojiconfig = value - - def load_kojiconfig(self): - """This loads the kojiconfig attribute - - This will either use the one passed in via arguments or a - secondary arch config depending on the package - """ - - # We have to allow this to work, even if we don't have a package - # we're working on, for things like gitbuildhash. - try: - self.module_name - except: - self._kojiconfig = self._orig_kojiconfig - return - for arch in self.secondary_arch.keys(): - if self.module_name in self.secondary_arch[arch]: - self._kojiconfig = os.path.expanduser('/etc/koji/%s-config' % - arch) - return - self._kojiconfig = self._orig_kojiconfig - - @cached_property - def cert_file(self): - """A client-side certificate for SSL authentication - - We override this from pyrpkg because we actually need a client-side - certificate. - """ - return os.path.expanduser('~/.fedora.cert') - - @cached_property - def ca_cert(self): - """A CA certificate to authenticate the server in SSL connections - - We override this from pyrpkg because we actually need a custom - CA certificate. - """ - return os.path.expanduser('~/.fedora-server-ca.cert') - - @cached_property - def lookasidecache(self): - """A helper to interact with the lookaside cache - - We override this because we need a different download path. - """ - return FedoraLookasideCache( - self.lookasidehash, self.lookaside, self.lookaside_cgi, - client_cert=self.cert_file, ca_cert=self.ca_cert) - - # Overloaded property loaders - def load_rpmdefines(self): - """Populate rpmdefines based on branch data""" - - # Determine runtime environment - self._runtime_disttag = self._determine_runtime_env() - - # We only match the top level branch name exactly. - # Anything else is too dangerous and --dist should be used - # This regex works until after Fedora 99. - if re.match(r'f\d\d$', self.branch_merge): - self._distval = self.branch_merge.split('f')[1] - self._distvar = 'fedora' - self.dist = 'fc%s' % self._distval - self.mockconfig = 'fedora-%s-%s' % (self._distval, self.localarch) - self.override = 'f%s-override' % self._distval - self._distunset = 'rhel' - # Works until RHEL 10 - elif re.match(r'el\d$', self.branch_merge) or \ - re.match(r'epel\d$', self.branch_merge): - self._distval = self.branch_merge.split('el')[1] - self._distvar = 'rhel' - self.dist = 'el%s' % self._distval - self.mockconfig = 'epel-%s-%s' % (self._distval, self.localarch) - self.override = 'epel%s-override' % self._distval - self._distunset = 'fedora' - elif re.match(r'olpc\d$', self.branch_merge): - self._distval = self.branch_merge.split('olpc')[1] - self._distvar = 'olpc' - self.dist = 'olpc%s' % self._distval - self.override = 'dist-olpc%s-override' % self._distval - self._distunset = 'rhel' - # master - elif re.match(r'master$', self.branch_merge): - self._distval = self._findmasterbranch() - self._distvar = 'fedora' - self.dist = 'fc%s' % self._distval - self.mockconfig = 'fedora-rawhide-%s' % self.localarch - self.override = None - self._distunset = 'rhel' - # If we don't match one of the above, punt - else: - raise pyrpkg.rpkgError('Could not find the dist from branch name ' - '%s\nPlease specify with --dist' % - self.branch_merge) - self._rpmdefines = ["--define '_sourcedir %s'" % self.path, - "--define '_specdir %s'" % self.path, - "--define '_builddir %s'" % self.path, - "--define '_srcrpmdir %s'" % self.path, - "--define '_rpmdir %s'" % self.path, - "--define 'dist .%s'" % self.dist, - "--define '%s %s'" % (self._distvar, - self._distval), - "--eval '%%undefine %s'" % self._distunset, - "--define '%s 1'" % self.dist] - if self._runtime_disttag: - if self.dist != self._runtime_disttag: - # This means that the runtime is known, and is different from - # the target, so we need to unset the _runtime_disttag - self._rpmdefines.append("--eval '%%undefine %s'" % - self._runtime_disttag) - - def load_target(self): - """This creates the target attribute based on branch merge""" - - if self.branch_merge == 'master': - self._target = 'rawhide' - else: - self._target = '%s-candidate' % self.branch_merge - - def load_user(self): - """This sets the user attribute, based on the Fedora SSL cert.""" - try: - self._user = fedora_cert.read_user_cert() - except Exception as e: - self.log.debug('Could not read Fedora cert, falling back to ' - 'default method: %s' % e) - super(Commands, self).load_user() - - # New functionality - def _findmasterbranch(self): - """Find the right "fedora" for master""" - - # If we already have a koji session, just get data from the source - if self._kojisession: - rawhidetarget = self.kojisession.getBuildTarget('rawhide') - desttag = rawhidetarget['dest_tag_name'] - return desttag.split('-')[0].replace('f', '') - - # Create a list of "fedoras" - fedoras = [] - - # Create a regex to find branches that exactly match f##. Should not - # catch branches such as f14-foobar - branchre = 'f\d\d$' - - # Find the repo refs - for ref in self.repo.refs: - # Only find the remote refs - if type(ref) == git.RemoteReference: - # Search for branch name by splitting off the remote - # part of the ref name and returning the rest. This may - # fail if somebody names a remote with / in the name... - if re.match(branchre, ref.name.split('/', 1)[1]): - # Add just the simple f## part to the list - fedoras.append(ref.name.split('/')[1]) - if fedoras: - # Sort the list - fedoras.sort() - # Start with the last item, strip the f, add 1, return it. - return(int(fedoras[-1].strip('f')) + 1) - else: - # We may not have Fedoras. Find out what rawhide target does. - try: - rawhidetarget = self.anon_kojisession.getBuildTarget( - 'rawhide') - except: - # We couldn't hit koji, bail. - raise pyrpkg.rpkgError('Unable to query koji to find rawhide \ - target') - desttag = rawhidetarget['dest_tag_name'] - return desttag.replace('f', '') - - def _determine_runtime_env(self): - """Need to know what the runtime env is, so we can unset anything - conflicting - """ - - try: - mydist = platform.linux_distribution() - except: - # This is marked as eventually being deprecated. - try: - mydist = platform.dist() - except: - runtime_os = 'unknown' - runtime_version = '0' - - if mydist: - runtime_os = mydist[0] - runtime_version = mydist[1] - else: - runtime_os = 'unknown' - runtime_version = '0' - - if runtime_os in ['redhat', 'centos']: - return 'el%s' % runtime_version - if runtime_os == 'Fedora': - return 'fc%s' % runtime_version - - # fall through, return None - return None - - def retire(self, message): - """Delete all tracked files and commit a new dead.package file - - Use optional message in commit. - - Runs the commands and returns nothing - """ - cmd = ['git'] - if self.quiet: - cmd.append('--quiet') - cmd.extend(['rm', '-rf', '.']) - self._run_command(cmd, cwd=self.path) - - fd = open(os.path.join(self.path, 'dead.package'), 'w') - fd.write(message + '\n') - fd.close() - - cmd = ['git', 'add', os.path.join(self.path, 'dead.package')] - self._run_command(cmd, cwd=self.path) - - self.commit(message=message) - - def update(self, bodhi_config, template='bodhi.template', bugs=[]): - """Submit an update to bodhi using the provided template.""" - - # build up the bodhi arguments, based on which version of bodhi is - # installed - bodhi_major_version = _get_bodhi_version()[0] - if bodhi_major_version < 2: - cmd = ['bodhi', '--bodhi-url', bodhi_config['url'], - '--new', '--release', self.branch_merge, - '--file', 'bodhi.template', self.nvr, '--username', - self.user] - elif bodhi_major_version == 2: - cmd = ['bodhi', '--bodhi-url', bodhi_config['url'], - 'updates', 'new', '--file', 'bodhi.template', - '--user', self.user, self.nvr] - else: - msg = 'This system has bodhi v{0}, which is unsupported.' - msg = msg.format(bodhi_major_version) - raise Exception(msg) - self._run_command(cmd, shell=True) - - def load_kojisession(self, anon=False): - try: - return super(Commands, self).load_kojisession(anon) - except pyrpkg.rpkgAuthError: - self.log.info("You might want to run fedora-packager-setup to " - "regenerate SSL certificate. For more info see " - "https://fedoraproject.org/wiki/Using_the_Koji_build" - "_system#Fedora_Account_System_.28FAS2.29_Setup") - raise - - -def _get_bodhi_version(): - """ - Use bodhi --version to determine the version of the Bodhi CLI that's - installed on the system, then return a list of the version components. - For example, if bodhi --version returns "2.1.9", this function will return - [2, 1, 9]. - """ - bodhi = subprocess.Popen(['bodhi', '--version'], stdout=subprocess.PIPE) - version = bodhi.communicate()[0].strip() - return [int(component) for component in version.split('.')] - - -if __name__ == "__main__": - from fedpkg.__main__ import main - main() diff --git a/src/fedpkg/__main__.py b/src/fedpkg/__main__.py deleted file mode 100644 index e46c418..0000000 --- a/src/fedpkg/__main__.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/python -# fedpkg - a script to interact with the Fedora Packaging system -# -# Copyright (C) 2011 Red Hat Inc. -# Author(s): Jesse Keating -# -# 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. See http://www.gnu.org/copyleft/gpl.html for -# the full text of the license. - -import argparse -import logging -import os -import sys - -import fedpkg -import pyrpkg -import pyrpkg.utils - -import six -if six.PY3: # SafeConfigParser == ConfigParser, former deprecated in >= 3.2 - from six.moves.configparser import ConfigParser -else: - from six.moves.configparser import SafeConfigParser as ConfigParser - - -cli_name = os.path.basename(sys.argv[0]) - - -def main(): - # Setup an argparser and parse the known commands to get the config file - parser = argparse.ArgumentParser(add_help=False) - parser.add_argument('-C', '--config', help='Specify a config file to use', - default='/etc/rpkg/%s.conf' % cli_name) - - (args, other) = parser.parse_known_args() - - # Make sure we have a sane config file - if not os.path.exists(args.config) and \ - not other[-1] in ['--help', '-h', 'help']: - sys.stderr.write('Invalid config file %s\n' % args.config) - sys.exit(1) - - # Setup a configuration object and read config file data - config = ConfigParser() - config.read(args.config) - - client = fedpkg.cli.fedpkgClient(config, name=cli_name) - client.do_imports(site='fedpkg') - client.parse_cmdline() - - if not client.args.path: - try: - client.args.path = pyrpkg.utils.getcwd() - except: - print('Could not get current path, have you deleted it?') - sys.exit(1) - - # setup the logger -- This logger will take things of INFO or DEBUG and - # log it to stdout. Anything above that (WARN, ERROR, CRITICAL) will go - # to stderr. Normal operation will show anything INFO and above. - # Quiet hides INFO, while Verbose exposes DEBUG. In all cases WARN or - # higher are exposed (via stderr). - log = pyrpkg.log - client.setupLogging(log) - - if client.args.v: - log.setLevel(logging.DEBUG) - elif client.args.q: - log.setLevel(logging.WARNING) - else: - log.setLevel(logging.INFO) - - # Run the necessary command - try: - sys.exit(client.args.command()) - except KeyboardInterrupt: - pass - except Exception as e: - log.error('Could not execute %s: %s' % - (client.args.command.__name__, e)) - if client.args.v: - raise - sys.exit(1) - -if __name__ == "__main__": - main() diff --git a/src/fedpkg/cli.py b/src/fedpkg/cli.py deleted file mode 100644 index 7c57d8f..0000000 --- a/src/fedpkg/cli.py +++ /dev/null @@ -1,210 +0,0 @@ -# cli.py - a cli client class module for fedpkg -# -# Copyright (C) 2011 Red Hat Inc. -# Author(s): Jesse Keating -# -# 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. See http://www.gnu.org/copyleft/gpl.html for -# the full text of the license. - -from pyrpkg.cli import cliClient -import sys -import os -import logging -import re -import textwrap -import hashlib - -import pkgdb2client - - -class fedpkgClient(cliClient): - def __init__(self, config, name=None): - self.DEFAULT_CLI_NAME = 'fedpkg' - super(fedpkgClient, self).__init__(config, name) - self.setup_fed_subparsers() - - def setup_fed_subparsers(self): - """Register the fedora specific targets""" - - self.register_retire() - self.register_update() - - # Target registry goes here - def register_retire(self): - """Register the retire target""" - - retire_parser = self.subparsers.add_parser( - 'retire', - help='Retire a package', - description='This command will remove all files from the repo, ' - 'leave a dead.package file, push the changes and ' - 'retire the package in pkgdb.' - ) - retire_parser.add_argument('reason', - help='Reason for retiring the package') - retire_parser.set_defaults(command=self.retire) - - def register_update(self): - update_parser = self.subparsers.add_parser( - 'update', - help='Submit last build as update', - description='This will create a bodhi update request for the ' - 'current package n-v-r.' - ) - update_parser.set_defaults(command=self.update) - - # Target functions go here - def retire(self): - try: - module_name = self.cmd.module_name - ns_module_name = self.cmd.ns_module_name - namespace = ns_module_name.split(module_name)[0].rstrip('/') - # Skip if package is already retired to allow to retire only in - # pkgdb - if os.path.isfile(os.path.join(self.cmd.path, 'dead.package')): - self.log.warn('dead.package found, package probably already ' - 'retired - will not remove files from git or ' - 'overwrite existing dead.package file') - else: - self.cmd.retire(self.args.reason) - self.push() - - pkgdb_config = dict(self.config.items('%s.pkgdb' % self.name)) - branch = self.cmd.branch_merge - pkgdb = pkgdb2client.PkgDB(url=pkgdb_config['url'], - login_callback=pkgdb2client.ask_password) - pkgdb.retire_packages(module_name, branch, namespace=namespace) - except Exception as e: - self.log.error('Could not retire package: %s' % e) - sys.exit(1) - - def _format_update_clog(self, clog): - ''' Format clog for the update template. ''' - lines = [l for l in clog.split('\n') if l] - if len(lines) == 0: - return "- Rebuilt.", "" - elif len(lines) == 1: - return lines[0], "" - log = ["# Changelog:"] - log.append('# - ' + lines[0]) - for l in lines[1:]: - log.append('# ' + l) - log.append('#') - return lines[0], "\n".join(log) - - def update(self): - template = """\ -[ %(nvr)s ] - -# bugfix, security, enhancement, newpackage (required) -type= - -# testing, stable -request=testing - -# Bug numbers: 1234,9876 -bugs=%(bugs)s - -%(changelog)s -# Here is where you give an explanation of your update. -notes=%(descr)s - -# Enable request automation based on the stable/unstable karma thresholds -autokarma=True -stable_karma=3 -unstable_karma=-3 - -# Automatically close bugs when this marked as stable -close_bugs=True - -# Suggest that users restart after update -suggest_reboot=False -""" - - bodhi_args = {'nvr': self.cmd.nvr, - 'bugs': '', - 'descr': 'Here is where you give an explanation' - ' of your update.'} - - # Extract bug numbers from the latest changelog entry - self.cmd.clog() - clog = file('clog').read() - bugs = re.findall(r'#([0-9]*)', clog) - if bugs: - bodhi_args['bugs'] = ','.join(bugs) - - # Use clog as default message - bodhi_args['descr'], bodhi_args['changelog'] = \ - self._format_update_clog(clog) - - template = textwrap.dedent(template) % bodhi_args - - # Calculate the hash of the unaltered template - orig_hash = hashlib.new('sha1') - orig_hash.update(template) - orig_hash = orig_hash.hexdigest() - - # Write out the template - out = file('bodhi.template', 'w') - out.write(template) - out.close() - - # Open the template in a text editor - editor = os.getenv('EDITOR', 'vi') - self.cmd._run_command([editor, 'bodhi.template'], shell=True) - - # Check to see if we got a template written out. Bail otherwise - if not os.path.isfile('bodhi.template'): - self.log.error('No bodhi update details saved!') - sys.exit(1) - # If the template was changed, submit it to bodhi - hash = self.cmd.lookasidecache.hash_file('bodhi.template', 'sha1') - if hash != orig_hash: - try: - bodhi_config = dict(self.config.items('%s.bodhi' % self.name)) - self.cmd.update(bodhi_config, template='bodhi.template') - except Exception as e: - self.log.error('Could not generate update request: %s' % e) - sys.exit(1) - else: - self.log.info('Bodhi update aborted!') - - # Clean up - os.unlink('bodhi.template') - os.unlink('clog') - -if __name__ == '__main__': - client = cliClient() - client._do_imports() - client.parse_cmdline() - - if not client.args.path: - try: - client.args.path = os.getcwd() - except: - print('Could not get current path, have you deleted it?') - sys.exit(1) - - # setup the logger -- This logger will take things of INFO or DEBUG and - # log it to stdout. Anything above that (WARN, ERROR, CRITICAL) will go - # to stderr. Normal operation will show anything INFO and above. - # Quiet hides INFO, while Verbose exposes DEBUG. In all cases WARN or - # higher are exposed (via stderr). - log = client.site.log - client.setupLogging(log) - - if client.args.v: - log.setLevel(logging.DEBUG) - elif client.args.q: - log.setLevel(logging.WARNING) - else: - log.setLevel(logging.INFO) - - # Run the necessary command - try: - client.args.command() - except KeyboardInterrupt: - pass diff --git a/src/fedpkg/lookaside.py b/src/fedpkg/lookaside.py deleted file mode 100644 index c679151..0000000 --- a/src/fedpkg/lookaside.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (c) 2015 - Red Hat Inc. -# -# 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. See http://www.gnu.org/copyleft/gpl.html for -# the full text of the license. - - -"""Interact with the Fedora lookaside cache - -We need to override the pyrpkg.lookasidecache module to handle our custom -download path. -""" - - -from pyrpkg.lookaside import CGILookasideCache - - -class FedoraLookasideCache(CGILookasideCache): - def __init__(self, hashtype, download_url, upload_url, - client_cert=None, ca_cert=None): - super(FedoraLookasideCache, self).__init__( - hashtype, download_url, upload_url, client_cert=client_cert, - ca_cert=ca_cert) - - self.download_path = ( - '%(name)s/%(filename)s/%(hashtype)s/%(hash)s/%(filename)s') diff --git a/src/fedpkg_man_page.py b/src/fedpkg_man_page.py deleted file mode 100755 index 0e7e1f3..0000000 --- a/src/fedpkg_man_page.py +++ /dev/null @@ -1,155 +0,0 @@ -# Print a man page from the help texts. - - -import sys -import datetime - - -# We could substitute the "" in .TH with the fedpkg version if we knew it -man_header = """\ -.\\" man page for fedpkg -.TH fedpkg 1 "%(today)s" "" "RPM packager" -.SH "NAME" -fedpkg \- RPM Packaging utility -.SH "SYNOPSIS" -.B "fedpkg" -[ -.I global_options -] -.I "command" -[ -.I command_options -] -[ -.I command_arguments -] -.br -.B "fedpkg" -.B "help" -.br -.B "fedpkg" -.I "command" -.B "\-\-help" -.SH "DESCRIPTION" -.B "fedpkg" -is a script to interact with the RPM Packaging system. -""" - -man_footer = """\ -.SH "SEE ALSO" -.UR "https://fedorahosted.org/fedora\-packager/" -.BR "https://fedorahosted.org/fedora\-packager/" -""" - - -class ManFormatter(object): - - def __init__(self, man): - self.man = man - - def write(self, data): - # print("MF: %r" % data) - for line in data.split('\n'): - # print('MFL: %s' % line) - self.man.write(' %s\n' % line) - - -def strip_usage(s): - """Strip "usage: " string from beginning of string if present""" - if s.startswith('usage: '): - return s.replace('usage: ', '', 1) - else: - return s - - -def man_constants(): - """Global constants for man file templates""" - today = datetime.date.today() - today_manstr = today.strftime('%Y\-%m\-%d') - return {'today': today_manstr} - - -def generate(parser, subparsers): - """\ - Generate the man page on stdout - - Given the argparse based parser and subparsers arguments, generate - the corresponding man page and write it to stdout. - """ - - # Not nice, but works: Redirect any print statement output to - # stderr to avoid clobbering the man page output on stdout. - man_file = sys.stdout - sys.stdout = sys.stderr - - mf = ManFormatter(man_file) - - choices = subparsers.choices - k = sorted(choices.keys()) - - man_file.write(man_header % man_constants()) - - helptext = parser.format_help() - helptext = strip_usage(helptext) - helptextsplit = helptext.split('\n') - helptextsplit = [line for line in helptextsplit - if not line.startswith(' -h, --help')] - - man_file.write('.SS "%s"\n' % ("Global Options",)) - - outflag = False - for line in helptextsplit: - if line == "optional arguments:": - outflag = True - elif line == "": - outflag = False - elif outflag: - man_file.write("%s\n" % line) - - help_texts = {} - for pa in subparsers._choices_actions: - help_texts[pa.dest] = getattr(pa, 'help', None) - - man_file.write('.SH "COMMAND OVERVIEW"\n') - - for command in k: - cmdparser = choices[command] - if not cmdparser.add_help: - continue - usage = cmdparser.format_usage() - usage = strip_usage(usage) - usage = ''.join(usage.split('\n')) - usage = ' '.join(usage.split()) - if help_texts[command]: - man_file.write('.TP\n.B "%s"\n%s\n' % (usage, help_texts[command])) - else: - man_file.write('.TP\n.B "%s"\n' % (usage)) - - man_file.write('.SH "COMMAND REFERENCE"\n') - for command in k: - cmdparser = choices[command] - if not cmdparser.add_help: - continue - - man_file.write('.SS "%s"\n' % cmdparser.prog) - - help = help_texts[command] - if help and not cmdparser.description: - if not help.endswith('.'): - help = "%s." % help - cmdparser.description = help - - h = cmdparser.format_help() - mf.write(h) - - man_file.write(man_footer) - - -if __name__ == '__main__': - try: - import fedpkg - except ImportError: - sys.path.append('src/') - import fedpkg - client = fedpkg.cli.fedpkgClient(config=None, name='fedpkg') - generate(client.parser, client.subparsers)