Package: devscripts Version: 2.11.7 Severity: wishlist Tags: patch Hi,
I've written a tool 'vcs-lint' (formerly 'mr-lint'[1]) for which I am looking for a home. It's not intended to be a purely Debian tool, but it's certainly what I use it for most, and it has some Debian-specific functionality. 'mr' and 'moreutils' are places I've considered which are not appropriate. Is devscripts a good fit? I don't feel it deserves it's own package, but I'd quite like to get it into wheezy if possible. Latest version attached. Sample usage/output: $ vcs-lint /home/jon/wd/bup: local branches not present in origin: fix-pythonoptimize,debian-proposed,debian-dump-s390 /home/jon/wd/bup: commits to local branch debian have not been pushed to origin /home/jon/wd/bup: 6 missing upstream tags: 0.14a, 0.17b, 0.20, 0.22a, 0.24b, 0.25~git2011.11.04 /home/jon/wd/bup: 8 missing debian tags: debian/0.17b-1, debian/0.20-2, debian/0.22a-1, debian/0.25~git2011.11.04-1, debian/0.25~git2011.11.04-2, debian/0.25~git2011.11.04-3, debian/0.25~git2011.11.04-4, debian/0.25~git2011.11.04-5 Please let me know what you think. Thanks! [1] http://jmtd.net/log/mr-lint/
#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright 2011 © Jon Dowland <j...@debian.org> # Licensed under the GNU GPL version 2 or higher. import sys, os, subprocess def usage(): print "usage: vcs-lint [ --verbose ]\n"+\ "vcs-lint will inspect the current working directory." exit(0) verbose = False if "--verbose" in sys.argv: verbose = True if "--help" in sys.argv: usage() def debug(str): if verbose: print str def run(cmd): p = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE) output, errors = p.communicate() return output # how many debian package versions are there? def get_package_versions(): output = run(['dpkg-parsechangelog', '--format', 'rfc822' , '--all']) return set([ x[9:] for x in output.split("\n") if "Version: " == x[:9] ]) def get_git_tags(): tags = set(filter(lambda x: x, run(["git", "tag", "-l"]).split("\n"))) debug("\ttags: %s" % ", ".join(sorted(tags))) return tags # git tag checking # there should be a tag 'upstream/$uv' and 'debian/$uv-$dv' for every version $v = "$uv-$dv" def missing_tags(repo,ttype,missing): if missing: print "%s: %d missing %s tags: %s" % (repo, len(missing), ttype, ", ".join(sorted(missing))) def check_package_versions_tagged(repo,git_tags,package_versions): debug("\tcheck_package_versions_tagged") if not filter(lambda x: x.find("-") >= 0, package_versions): # native package missing_tags(repo, "package version", package_versions - git_tags) else: prefix = "" if filter(lambda x: x.find("upstream") == 0, git_tags): prefix = "upstream/" missing_tags(repo, "upstream", set( [ "%s%s"%(prefix,x[:x.find("-")]) for x in package_versions if x.find("-") >= 0 ]) - git_tags) missing_tags(repo, "debian", set(["debian/%s"%x for x in package_versions]) - git_tags) # git branch checking def get_git_branches(prefix): branches = run(["git", "for-each-ref", '--format=%(refname)', prefix]).split("\n") return set([ x[len(prefix):] for x in branches if prefix == x[:len(prefix)] ]) def get_git_local_branches(): return get_git_branches("refs/heads/") def get_git_origin_branches(): return get_git_branches("refs/remotes/origin/") # are all local branches represented at origin? def check_local_branches_at_origin(repo,origin_branches,local_branches): debug("\tcheck_local_branches_at_origin") debug("\t\tlocal branches: %s" % ",".join(local_branches)) debug("\t\torigin branches: %s" % ",".join(origin_branches)) missing = local_branches - origin_branches if missing: print "%s: local branches not present in origin: %s" % (repo, ",".join(missing)) # is branch x ahead of origin/x? def local_branch_ahead_of_origin(branch): debug("\tlocal_branch_ahead_of_origin") return bool(run(["git", "rev-list", branch, "^remotes/origin/%s" % branch, "--"])) # do all local branches match origin branches of the same name? def check_branches_match_origin (repo,origin_branches,local_branches): debug("\tcheck_branches_match_origin") for b in local_branches & origin_branches: debug("\t\t%s" % b) l = run(["git", "for-each-ref",'--format="%(objectname)', "refs/remotes/origin/%s" % b]) r = run(["git", "for-each-ref",'--format="%(objectname)', "refs/heads/%s" % b]) if r != l: if local_branch_ahead_of_origin(b): print "%s: commits to local branch %s have not been pushed to origin" % (repo,b) else: print "%s: local branch %s does not match origin branch %s" % (repo,b,b) def is_gitrepo(): return os.path.isdir(".git") def repo_is_debian_package(): return os.path.isfile("debian/changelog") repo = os.getcwd() if not is_gitrepo: sys.stderr.write("%s: not a git repository\n" % repo) exit(1) origin_branches = get_git_origin_branches() local_branches = get_git_local_branches() check_local_branches_at_origin(repo, origin_branches, local_branches) check_branches_match_origin(repo, origin_branches, local_branches) if repo_is_debian_package: package_versions = get_package_versions() git_tags = get_git_tags() check_package_versions_tagged(repo, git_tags, package_versions)