#compdef gbp
#description build Debian packages from a Git repository

__gbp_common_options() {
	local prefix="$1"
	# these can't be prefixed
	_arguments '--help[Show help]' \
		'--version[Show version information]'

	_arguments "--${prefix}verbose[Verbose execution]" \
		"--${prefix}color=-[Use colored output]:color:(on auto off)"
}

__gbp_branch_options() {
	local prefix="$1"
	_arguments \
		"--${prefix}debian-branch=-[The branch the Debian package is being developed on]" \
		"--${prefix}upstream-branch=-[The branch the upstream  sources  are  put onto]" \
		"--${prefix}pristine-tar[Track pristine tar branch]"
}

__gbp_tag_format_options() {
	local prefix="$1"
	_arguments \
		"--${prefix}debian-tag=-[format string for debian tags]" \
		"--${prefix}upstream-tag=-[format string for upstream tags]"
}

__gbp_tag_sign_options() {
	local prefix="$1"
	_arguments \
		"(--${prefix}sign-tags --${prefix}no-sign-tags)--${prefix}sign-tags[GPG sign all generated tags]" \
		"(--${prefix}sign-tags --${prefix}no-sign-tags)--${prefix}no-sign-tags[Do not GPG sign generated tags]" \
		"--${prefix}keyid=-[GPG keyid to sign tags with]:GPG key:"
}

_gbp() {
	local curcontext="$curcontext" state line
	typeset -A opt_args
	_arguments -C \
		':command:->command' \
		'*::options:->options' \

	case $state in
	(command)
		#breaks if defined outside the func
		local -a subcommands
		subcommands=(
			'buildpackage:Build a Debian package'
			'clone:Clone a Git repository from a remote and set up the necessary branch tracking'
			'config:Query configuration values'
			'create-remote-repo:Create a remote Git repository'
			'dch:Generate the debian/changelog from  Git commit history'
			'export-orig:Create orig tarballs from git'
			'import-dsc:Import a single Debian source package'
			'import-dscs:Import multiple Debian source packages'
			'import-orig:Import a new upstream tarball'
			'import-ref:Update upstream sources when using Git only'
			'pq:Manage debian/patches using Git rebase'
			'pristine-tar:Manage pristine-tar commits in a git repository'
			'pull:Update a Git repository from a remote'
			'push:Push Debian packaging changes to a Git remote'
			'tag:Tag a Debian packages in a Git repository'
		)

		_describe -t commands gbp subcommands
	;;
	(options)
		local funcname
		funcname=_gbp-$line[1]
		if type $funcname | grep -q "shell function" ; then
			$funcname
		fi
	;;
	esac
}

_gbp-buildpackage() {
	__gbp_common_options git-
	__gbp_branch_options git-
	__gbp_tag_format_options git-
	__gbp_tag_sign_options git-
	_arguments \
	  '--git-ignore-new[build with uncommitted changes in the source tree]' \
	  '--git-no-ignore-new[negates --git-ignore-new]' \
	  '--git-tag[create a tag after a successful build]' \
	  '--git-tag-only[do not build, only tag and run the posttag hook]' \
	  '--git-retag[do not fail if the tag already exists]' \
	  '--git-force-create[force creation of orig.tar.gz]' \
	  '--git-no-create-orig[do not create orig.tar.gz]' \
	  '--git-tarball-dir=-[location to look for external tarballs]:tarball directory:_files -/' \
	  '--git-compression=-[compression type]:compression:(auto gzip bzip2 lzma xz)' \
	  '--git-compression-level=-[set compression level]:level:(1 2 3 4 5 6 7 8 9)' \
	  '--git-ignore-branch[build although debian-branch != current branch]' \
	  '--git-no-ignore-branch[negates --git-ignore-branch]' \
	  '--git-builder=-[command to build the Debian package]:command:' \
	  '--git-cleaner=-[command to clean the working copy]:command:' \
	  '--git-prebuild=-[command to run before a build]:command:' \
	  '--git-postbuild=-[hook run after a successful build]:command:' \
	  '--git-posttag=-[hook run after a successful tag operation]:command:' \
	  '--git-pbuilder[invoke git-pbuilder for building]' \
	  '--git-no-pbuilder[negates --git-pbuilder]' \
	  '--git-dist=-[build for this distribution when using git-pbuilder]:distribution:' \
	  '--git-arch=-[build for this architecture when using git-pbuilder]:architecture:' \
	  '--git-export-dir=-[before building the package export the source into this directory]:directory:_files -/' \
	  '--git-export=-[export treeish object instead of HEAD]:treeish:' \
	  '--git-dont-purge[retain exported package build directory]' \
	  '--git-overlay[extract orig tarball when using export-dir option]' \
	  '--git-no-overlay[negates --git-overlay]' \
	  '--git-notify=-[Send a desktop notification after build]:notify:(on auto off)' \
	  '*:Other options:_dpkg-buildpackage'
}

_gbp-clone() {
	__gbp_common_options
	__gbp_branch_options
	_arguments \
		'--all[Track all branches, not only debian and upstream]'
}

_gbp-create-remote-repo() {
	__gbp_common_options
	_arguments \
		'--remote-url-pattern=-[Where to create remote repository]' \
		'--remote-name=-[What  name  git  will use when referring to that repository]' \
		'--template-dir=-[Template dir to pass to git init]' \
		'--remote-config=-[Name of config file section to specify params]' \
		'(--track --no-track)--track[Set up branch tracking]' \
		'(--track --no-track)--no-track[Do not set up branch tracking]'

}

_gbp-dch () {
	__gbp_common_options
	__gbp_branch_options
	__gbp_tag_format_options

	_arguments \
		'--ignore-branch[build although debian-branch != current branch]' \
		'--since=-[Start point for reading commits]:commit-ish:' \
		'--auto[Guess the last commit documented in the changelog]' \
		'(--meta --no-meta)--meta[Parse meta tags]' \
		'(--meta --no-meta)--no-meta[Do not parse meta tags]' \
		'--meta-closes=-[What meta tags to look for  to  generate  bug-closing  changelog entries]' \
		'--meta-closes-bugnum=-[What bug number format to look for to generate bug-closing changelog entries]' \
		'(--full --no-full)--full[Include the full commit message]' \
		'(--full --no-full)--no-full[Do not include the full commit message]' \
		'(--snapshot -S)'{-S,--snapshot}'[Create a snapshot release entry]' \
		'--snapshot-number=-[Python expression that gets eval()ed to the new snapshot number]' \
		'(--release -R)'{-R,--release}'[Remove any snapshot release banners]' \
		'(--new-version -N)'{-R,--release}'=[Specify changelog version]' \
		'--team[Create a team upload entry]' \
		'--bpo[Increment the release number for a backports upload]' \
		'--nmu[Increment the release number for a NMU upload]' \
		'--qa[Increment the release number for a QA upload]' \
		'(--local -l)'{-l,--local}'=-[Increment the release number for a local build]' \
		'--distribution=-[Set the distribution field]' \
		'--force-distribution[Force distribution]' \
		'--urgency=-[Set the upload urgency]' \
		'--git-log=-[Options passed to git log]' \
		'--id-length=-[Number of commit id digits to include]' \
		'--ignore-regex=-[Ignore matching commit lines]' \
		'--git-author[Use git name configuration for changelog signature]' \
		'(--multimaint-merge --no-multimaint-merge)--multimaint-merge[Merge commits by maintainer]' \
		'(--multimaint-merge --no-multimaint-merge)--multimaint-merge[Do not merge commits by maintainer]' \
		'--spawn-editor=[Spawn an editor]:when:(always never snapshot release)' \
		'--commit-msg=[Commit message format string]' \
		'--commit[Commit the generated changelog]' \
		'*:Paths:_files -/'
}

_gbp-import-dsc() {
	__gbp_common_options
	__gbp_branch_options
	__gbp_tag_format_options
	__gbp_tag_sign_options
	_arguments \
		'--filter=-[Filter out files]' \
		'--allow-unauthenticated[Skip signature verification on downloads]' \
		'--allow-same-version[Import a package with the same debian version]' \
		'--author-is-committer[Use the author identity as committer identity]' \
		'--author-date-is-committer-date[Use author date as commit date]' \
		'*:package:_files -g "*.dsc"'
	# TODO: complete source package names
	# TODO: pass only one tarball/source package name
}

_gbp-import-dscs() {
	# same options
	_gbp-import-dsc
	_arguments \
		'--debsnap[Fetch snapshots from snapshots.debian.org]' \
		'--ignore-repo-config[Ignore options in gbp.conf]'
	# TODO: multiple dscs or one source package name + debsnap
}

_gbp-import-orig() {
	__gbp_common_options
	__gbp_branch_options
	__gbp_tag_format_options
	__gbp_tag_sign_options
	_arguments \
		'(--upstream-version -u)'{--upstream-version,-u}'=[The upstream version number]' \
		'--merge[Merge the upstream branch into the debian branch]' \
		'--upstream-vcs-tag=-[Add a tag as an additional parent to the upstream tarball commit]' \
		'--import-msg=-[Commit message format string]' \
		'--filter=-[Filter out files]' \
		'--filter-pristine-tar[When filtering also filter out of pristine-tar tarballs]' \
		'(--symlink-orig --no-symlink-orig)--symlink-orig=[Create a symlink with a debian-compliant name]' \
		'(--symlink-orig --no-symlink-orig)--no-symlink-orig=[Do not create a symlink with a debian-compliant name]' \
		'--postimport=-[Run a command after import]' \
		'--uscan[Use uscan to fetch the new upstream version]' \
		'*:file:_files'

	# TODO: pass only one tarball
	# TODO: Do not complete files when uscan option is enabled
}

_gbp-pq() {
	__gbp_common_options
	_arguments \
		'(--patch-numbers --no-patch-numbers)--patch-numbers[Add numbers to patch files]' \
		'(--patch-numbers --no-patch-numbers)--no-patch-numbers[Do not add numbers to patch files]' \
		'--topic=-[Topic to use when importing a single patch]' \
		'--time-machine=-[Go back N commits trying to apply patch queue]'

	local -a pqcommands
	pqcommands=(
		'import:Create   a   patch   queue   branch'
		'export:Export the patches on the patch-queue branch'
		'rebase:Rebase the  patch-queue  branch against the current branch'
		'drop:Drop the patch queue'
		'apply:Add  a  single patch to the patch-queue'
		'switch:Switch to the patch-queue branch if on the base branch and viceversa'
	)
	# TODO: only display these commands once
	_describe -t pqcommands gbp-pq pqcommands
}

_gbp-pull() {
	__gbp_common_options
	__gbp_branch_options
	_arguments \
		'--force[Update even non fast-forward]' \
		'--redo-pq[Rebuild the patch queue]' \
		'--ignore-branch[Do not care if on a detached state]' \
		'--depth=-[Depth for deepening shallow clones]'
}

_gbp "$@"



__gbp_common_options() {
	local prefix="$1"
	# these can't be prefixed
	_arguments '--help[Show help]' \
		'--version[Show version information]'

	_arguments "--${prefix}verbose[Verbose execution]" \
		"--${prefix}color=-[Use colored output]:color:(on auto off)"

}

__gbp_branch_options() {
	local prefix="$1"
	_arguments \
		"--${prefix}debian-branch=-[The branch the Debian package is being developed on]" \
		"--${prefix}upstream-branch=-[The branch the upstream  sources  are  put onto]" \
		"--${prefix}pristine-tar[Track pristine tar branch]"
}

__gbp_tag_format_options() {
	local prefix="$1"
	_arguments \
		"--${prefix}debian-tag=-[format string for debian tags]" \
		"--${prefix}upstream-tag=-[format string for upstream tags]"
}

__gbp_tag_sign_options() {
	local prefix="$1"
	_arguments \
		"(--${prefix}sign-tags --${prefix}no-sign-tags)--${prefix}sign-tags[GPG sign all generated tags]" \
		"(--${prefix}sign-tags --${prefix}no-sign-tags)--${prefix}no-sign-tags[Do not GPG sign generated tags]" \
		"--${prefix}keyid=-[GPG keyid to sign tags with]:GPG key:"
}

_gbp() {
	local curcontext="$curcontext" state line
	typeset -A opt_args
	_arguments -C \
		':command:->command' \
		'*::options:->options' \

	case $state in
	(command)
		#breaks if defined outside the func
		local -a subcommands
		subcommands=(
			'buildpackage:Build a Debian package'
			'clone:Clone  a  Git  repository from a remote and set up the necessary branch tracking.'
			'create-remote-repo:Create a remote Git repository'
			'dch:Generate the debian/changelog from  Git commit history'
			'import-dsc:Import a single Debian source package'
			'import-dscs:Import multiple Debian source packages'
			'import-orig:Import a new upstream tarball'
			'pq:Manage debian/patches using Git rebase'
			'pull:Update a Git repository from a remote'
		)

		_describe -t commands gbp subcommands
	;;
	(options)
		local funcname
		funcname=_gbp-$line[1]
		if type $funcname | grep -q "shell function" ; then
			$funcname
		fi
	;;
	esac
}

_gbp-buildpackage() {
	__gbp_common_options git-
	__gbp_branch_options git-
	__gbp_tag_format_options git-
	__gbp_tag_sign_options git-
	_arguments \
	  '--git-ignore-new[build with uncommitted changes in the source tree]' \
	  '--git-no-ignore-new[negates --git-ignore-new]' \
	  '--git-tag[create a tag after a successful build]' \
	  '--git-tag-only[do not build, only tag and run the posttag hook]' \
	  '--git-retag[do not fail if the tag already exists]' \
	  '--git-force-create[force creation of orig.tar.gz]' \
	  '--git-no-create-orig[do not create orig.tar.gz]' \
	  '--git-tarball-dir=-[location to look for external tarballs]:tarball directory:_files -/' \
	  '--git-compression=-[compression type]:compression:(auto gzip bzip2 lzma xz)' \
	  '--git-compression-level=-[set compression level]:level:(1 2 3 4 5 6 7 8 9)' \
	  '--git-ignore-branch[build although debian-branch != current branch]' \
	  '--git-no-ignore-branch[negates --git-ignore-branch]' \
	  '--git-builder=-[command to build the Debian package]:command:' \
	  '--git-cleaner=-[command to clean the working copy]:command:' \
	  '--git-prebuild=-[command to run before a build]:command:' \
	  '--git-postbuild=-[hook run after a successful build]:command:' \
	  '--git-posttag=-[hook run after a successful tag operation]:command:' \
	  '--git-pbuilder[invoke git-pbuilder for building]' \
	  '--git-no-pbuilder[negates --git-pbuilder]' \
	  '--git-dist=-[build for this distribution when using git-pbuilder]:distribution:' \
	  '--git-arch=-[build for this architecture when using git-pbuilder]:architecture:' \
	  '--git-export-dir=-[before building the package export the source into this directory]:directory:_files -/' \
	  '--git-export=-[export treeish object instead of HEAD]:treeish:' \
	  '--git-dont-purge[retain exported package build directory]' \
	  '--git-overlay[extract orig tarball when using export-dir option]' \
	  '--git-no-overlay[negates --git-overlay]' \
	  '--git-notify=-[Send a desktop notification after build]:notify:(on auto off)' \
	  '*:Other options:_dpkg-buildpackage'
}

_gbp-clone() {
	__gbp_common_options
	__gbp_branch_options
	_arguments \
		'--all[Track all branches, not only debian and upstream]'
}

_gbp-create-remote-repo() {
	__gbp_common_options
	_arguments \
		'--remote-url-pattern=-[Where to create remote repository]' \
		'--remote-name=-[What  name  git  will use when referring to that repository]' \
		'--template-dir=-[Template dir to pass to git init]' \
		'--remote-config=-[Name of config file section to specify params]' \
		'(--track --no-track)--track[Set up branch tracking]' \
		'(--track --no-track)--no-track[Do not set up branch tracking]'
}

_gbp-dch () {
	__gbp_common_options
	__gbp_branch_options
	__gbp_tag_format_options

	_arguments \
		'--ignore-branch[build although debian-branch != current branch]' \
		'--since=-[Start point for reading commits]:commit-ish:' \
		'--auto[Guess the last commit documented in the changelog]' \
		'(--meta --no-meta)--meta[Parse meta tags]' \
		'(--meta --no-meta)--no-meta[Do not parse meta tags]' \
		'--meta-closes=-[What meta tags to look for  to  generate  bug-closing  changelog entries]' \
		'--meta-closes-bugnum=-[What bug number format to look for to generate bug-closing changelog entries]' \
		'(--full --no-full)--full[Include the full commit message]' \
		'(--full --no-full)--no-full[Do not include the full commit message]' \
		'(--snapshot -S)'{-S,--snapshot}'[Create a snapshot release entry]' \
		'--snapshot-number=-[Python expression that gets eval()ed to the new snapshot number]' \
		'(--release -R)'{-R,--release}'[Remove any snapshot release banners]' \
		'(--new-version -N)'{-R,--release}'=[Specify changelog version]' \
		'--team[Create a team upload entry]' \
		'--bpo[Increment the release number for a backports upload]' \
		'--nmu[Increment the release number for a NMU upload]' \
		'--qa[Increment the release number for a QA upload]' \
		'--distribution=-[Set the distribution field]' \
		'--force-distribution[Force distribution]' \
		'--urgency=-[Set the upload urgency]' \
		'--git-log=-[Options passed to git log]' \
		'--id-length=-[Number of commit id digits to include]' \
		'--ignore-regex=-[Ignore matching commit lines]' \
		'--git-author[Use git name configuration for changelog signature]' \
		'(--multimaint-merge --no-multimaint-merge)--multimaint-merge[Merge commits by maintainer]' \
		'(--multimaint-merge --no-multimaint-merge)--multimaint-merge[Do not merge commits by maintainer]' \
		'--spawn-editor=[Spawn an editor]:when:(always never snapshot release)' \
		'--commit-msg=[Commit message format string]' \
		'--commit[Commit the generated changelog]' \
		'*:Paths:_files -/'
}

_gbp-import-dsc() {
	__gbp_common_options
	__gbp_branch_options
	__gbp_tag_format_options
	__gbp_tag_sign_options
	_arguments \
		'--filter=-[Filter out files]' \
		'--allow-unauthenticated[Skip signature verification on downloads]' \
		'--allow-same-version[Import a package with the same debian version]' \
		'--author-is-committer[Use the author identity as committer identity]' \
		'--author-date-is-committer-date[Use author date as commit date]' \
		'*:package:_files -g "*.dsc"'
	# TODO: complete source package names
	# TODO: pass only one tarball/source package name
}

_gbp-import-dscs() {
	# same options
	_gbp-import-dsc
	_arguments \
		'--debsnap[Fetch snapshots from snapshots.debian.org]' \
		'--ignore-repo-config[Ignore options in gbp.conf]'
	# TODO: multiple dscs or one source package name + debsnap
}

_gbp-import-orig() {
	__gbp_common_options
	__gbp_branch_options
	__gbp_tag_format_options
	__gbp_tag_sign_options
	_arguments \
		'(--upstream-version -u)'{--upstream-version,-u}'=[The upstream version number]' \
		'--merge[Merge the upstream branch into the debian branch]' \
		'--upstream-vcs-tag=-[Add a tag as an additional parent to the upstream tarball commit]' \
		'--import-msg=-[Commit message format string]' \
		'--filter=-[Filter out files]' \
		'--filter-pristine-tar[When filtering also filter out of pristine-tar tarballs]' \
		'(--symlink-orig --no-symlink-orig)--symlink-orig=[Create a symlink with a debian-compliant name]' \
		'(--symlink-orig --no-symlink-orig)--no-symlink-orig=[Do not create a symlink with a debian-compliant name]' \
		'--postimport=-[Run a command after import]' \
		'--uscan[Use uscan to fetch the new upstream version]' \
		'*:file:_files'

	# TODO: pass only one tarball
	# TODO: Do not complete files when uscan option is enabled
}

_gbp-pq() {
	__gbp_common_options
	_arguments \
		'(--patch-numbers --no-patch-numbers)--patch-numbers[Add numbers to patch files]' \
		'(--patch-numbers --no-patch-numbers)--no-patch-numbers[Do not add numbers to patch files]' \
		'--topic=-[Topic to use when importing a single patch]' \
		'--time-machine=-[Go back N commits trying to apply patch queue]'

	local -a pqcommands
	pqcommands=(
		'import:Create   a   patch   queue   branch'
		'export:Export the patches on the patch-queue branch'
		'rebase:Rebase the  patch-queue  branch against the current branch'
		'drop:Drop the patch queue'
		'apply:Add  a  single patch to the patch-queue'
		'switch:Switch to the patch-queue branch if on the base branch and viceversa'
	)
	# TODO: only display these commands once
	_describe -t pqcommands gbp-pq pqcommands
}

_gbp-pull() {
	__gbp_common_options
	__gbp_branch_options
	_arguments \
		'--all[Update all remote-tracking branches that have identical name in the remote]' \
		'--depth=-[Depth for deepening shallow clones]' \
		'--force[Update even non fast-forward]' \
		'--ignore-branch[Do not care if on a detached state]' \
		'--no-ignore-branch[Negates --ignore-branch]' \
		'--no-pristine-tar[Negates --pristine-tar]' \
		'--no-track-missing[Negates --track-missing]' \
		'--redo-pq[Rebuild the patch queue]' \
		'--track-missing[Track missing remote branches, default is "False"]'
}

_gbp-push() {
	__gbp_common_options
	__gbp_branch_options
	__gbp_tag_format_options
	_arguments \
		'--dry-run[Dry run, do not push]' \
		'--ignore-branch[Do not care if on a detached state]' \
		'--no-ignore-branch[Negates --ignore-branch]'
}

_gbp-import-ref() {
	__gbp_common_options
        __gbp_tag_sign_options
	_arguments \
		'--debian-branch=-[The branch the Debian package is being developed on]' \
		'--keyid=-[Use this keyid for gpg signing tags]' \
		'--merge-mode=-[How to fold the upstream commits onto the Debian packaging branch]' \
		'--no-rollback[Do not rollback changes in case of an error]' \
		'--postimport=-[Run cmd after the import]' \
		'--rollback[Rollback changes in case of an error]' \
		'--upstream-branch=-[The branch the upstream sources are put onto]' \
		'--upstream-tag=-[Format string for upstream tags]' \
		'--upstream-tree=-[What to merge into the debian-branch]:tree:(BRANCH TAG TREEISH)' \
		'--upstream-version=-[The upstream version to merge]'
}

_gbp-export-orig() {
	__gbp_common_options
	_arguments \
		'--component=-[Component name for additional tarballs]' \
		'--compression=-[Compression type]:compression:(auto gzip bzip2 lzma xz)' \
		'--compression-level=-[Set compression level]:level:(1 2 3 4 5 6 7 8 9)' \
		'--force-create[Force creation of orig tarball]' \
		'--no-pristine-tar[Negates --pristine-tar]' \
		'--no-submodules[Negates --submodules]' \
		'--pristine-tar[Use pristine-tar to create orig tarball]' \
		'--submodules[Transparently handle submodules in the upstream tree]' \
		'--tarball-dir=-[Location to look for external tarballs]:tarball directory:_files -/' \
		'--upstream-branch=-[The branch the upstream sources are put onto]' \
		'--upstream-signatures=-[Use upstream signature]' \
		'--upstream-tag=-[Format string for upstream tags]' \
		'--upstream-tree=-[What to merge into the debian-branch]:tree:(BRANCH TAG TREEISH)'
}

_gbp-pristine-tar() {
	__gbp_common_options
	_arguments \
		'--component=-[Component name for additional tarballs]' \
		'--upstream-tag=-[Format string for upstream tags]'
}

_gbp-tag() {
	__gbp_common_options
	__gbp_tag_sign_options
	_arguments \
		'--debian-branch=-[The branch the Debian package is being developed on]' \
		"--debian-tag=-[Format string for debian tags]" \
		"--debian-tag-msg=-[Format string for signed debian-tag messages]" \
		'--git-no-ignore-branch[Negates --git-ignore-branch]' \
		'--ignore-branch[Do not care if on a detached state]' \
		'--ignore-new[Build with uncommitted changes in the source tree]' \
		'--no-ignore-new[Negates --git-ignore-new]' \
		'--posttag=-[Hook run after a successful tag operation]:command:' \
		'--retag[Do not fail if the tag already exists]'
}

_gbp-config() {
	__gbp_common_options
}

_gbp "$@"
