]> arthur.barton.de Git - bup.git/blob - lib/bup/cmd/tag.py
Fully (and explicitly) close PackIdxLists
[bup.git] / lib / bup / cmd / tag.py
1
2 from __future__ import absolute_import
3 from binascii import hexlify
4 import sys
5
6 from bup import git, options
7 from bup.compat import argv_bytes
8 from bup.helpers import debug1, log
9 from bup.io import byte_stream, path_msg
10
11
12 # FIXME: review for safe writes.
13
14 optspec = """
15 bup tag
16 bup tag [-f] <tag name> <commit>
17 bup tag [-f] -d <tag name>
18 --
19 d,delete=   Delete a tag
20 f,force     Overwrite existing tag, or ignore missing tag when deleting
21 """
22
23 def main(argv):
24     o = options.Options(optspec)
25     opt, flags, extra = o.parse_bytes(argv[1:])
26
27     git.check_repo_or_die()
28
29     tags = [t for sublist in git.tags().values() for t in sublist]
30
31     if opt.delete:
32         # git.delete_ref() doesn't complain if a ref doesn't exist.  We
33         # could implement this verification but we'd need to read in the
34         # contents of the tag file and pass the hash, and we already know
35         # about the tag's existance via "tags".
36         tag_name = argv_bytes(opt.delete)
37         if not opt.force and tag_name not in tags:
38             log("error: tag '%s' doesn't exist\n" % path_msg(tag_name))
39             sys.exit(1)
40         tag_file = b'refs/tags/%s' % tag_name
41         git.delete_ref(tag_file)
42         sys.exit(0)
43
44     if not extra:
45         for t in tags:
46             sys.stdout.flush()
47             out = byte_stream(sys.stdout)
48             out.write(t)
49             out.write(b'\n')
50         sys.exit(0)
51     elif len(extra) != 2:
52         o.fatal('expected commit ref and hash')
53
54     tag_name, commit = map(argv_bytes, extra[:2])
55     if not tag_name:
56         o.fatal("tag name must not be empty.")
57     debug1("args: tag name = %s; commit = %s\n"
58            % (path_msg(tag_name), commit.decode('ascii')))
59
60     if tag_name in tags and not opt.force:
61         log("bup: error: tag '%s' already exists\n" % path_msg(tag_name))
62         sys.exit(1)
63
64     if tag_name.startswith(b'.'):
65         o.fatal("'%s' is not a valid tag name." % path_msg(tag_name))
66
67     try:
68         hash = git.rev_parse(commit)
69     except git.GitError as e:
70         log("bup: error: %s" % e)
71         sys.exit(2)
72
73     if not hash:
74         log("bup: error: commit %s not found.\n" % commit.decode('ascii'))
75         sys.exit(2)
76
77     with git.PackIdxList(git.repo(b'objects/pack')) as pL:
78         if not pL.exists(hash):
79             log("bup: error: commit %s not found.\n" % commit.decode('ascii'))
80             sys.exit(2)
81
82     tag_file = git.repo(b'refs/tags/' + tag_name)
83     try:
84         tag = open(tag_file, 'wb')
85     except OSError as e:
86         log("bup: error: could not create tag '%s': %s" % (path_msg(tag_name), e))
87         sys.exit(3)
88     with tag as tag:
89         tag.write(hexlify(hash))
90         tag.write(b'\n')