diff options
-rw-r--r-- | egg-author.py | 125 |
1 files changed, 107 insertions, 18 deletions
diff --git a/egg-author.py b/egg-author.py index c897f04..ddeeb54 100644 --- a/egg-author.py +++ b/egg-author.py @@ -24,37 +24,42 @@ from mercurial import cmdutil, commands, util import mercurial.match as matchmod # This is probably really really dumb code. I don't know python -def _find_release_info_file(repo): +def _find_egg_info_file(repo, type): stat = repo.status(clean=True) for x in stat[:5]: for fn in x: - if fnmatch.fnmatch(fn, '*.release-info'): + if fnmatch.fnmatch(fn, '*.%s' % type): raise util.Abort(_('%s is modified (please commit or revert ' 'and retry)') % fn) - release_info_file = None + egg_info_file = None - for x in stat[5:]: + for x in stat[6:]: for fn in x: - if fnmatch.fnmatch(fn, "*.release-info"): - if release_info_file: - raise util.Abort(_('Found more than one release-info file!')) + if fnmatch.fnmatch(fn, "*.%s" % type): + if egg_info_file: + raise util.Abort(_('Found more than one %s file!' % type)) else: - release_info_file = fn + egg_info_file = fn - if not release_info_file: - raise util.Abort(_('Could not find release-info file. You need to ' - 'create one first. See %s for more info.') - % 'http://wiki.call-cc.org/releasing-your-egg') + if not egg_info_file: + if type == 'release-info': + help_uri = 'http://wiki.call-cc.org/releasing-your-egg' + elif type == 'meta': + help_uri = 'http://wiki.call-cc.org/Metafile%20reference' + else: + raise util.Abort(_('No help URI for egg file type %s') % type) + raise util.Abort(_('Could not find %s file. You need to ' + 'create one first. See %s for more info.') % help_uri) - return release_info_file + return egg_info_file -def _clean_scheme_string(s): +def _to_scheme_string(s): # This is a pathetic attempt at being safe. You shouldn't be using # these names anywway, and the user should be already be trusted when # they're allowed to commit. - return re.sub(r'\\', r'\\\\', re.sub(r'"', r'\\"', s)) + return '"' + re.sub(r'\\', r'\\\\', re.sub(r'"', r'\\"', s)) + '"' def eggtag(ui, repo, name1, *names, **opts): '''Tag a Chicken egg for release. @@ -65,7 +70,7 @@ def eggtag(ui, repo, name1, *names, **opts): ''' allnames = [t.strip() for t in (name1,) + names] - release_info_file = _find_release_info_file(repo) + release_info_file = _find_egg_info_file(repo, 'release-info') fp = repo.wfile(release_info_file, 'r+') commands.tag(ui, repo, name1, *names, **opts) @@ -73,12 +78,93 @@ def eggtag(ui, repo, name1, *names, **opts): relinfo_message = ('Updated release-info file for release tag %s' % (', '.join(allnames))) fp.seek(0, 2) # to the end for n in allnames: - fp.write("(release \"%s\")\n" % _clean_scheme_string(n)) + fp.write("(release %s)\n" % _to_scheme_string(n)) fp.close() m = matchmod.exact(repo.root, '', [release_info_file]) repo.commit(text=relinfo_message, user=opts.get('user'), date=opts.get('date'), match=m) +def read_byte(f,res): + byte = f.read(1) + if (len(byte) == 0): + return None + else: + res.extend(byte[0]) + return byte[0] + +class FoundFiles(Exception): + def __init__(self, val): + self.res = val + +# A *really* hacky s-expression reader +def _read_over_files(f, res, end = None): + byte = read_byte(f,res) + + first_identifier = True + + while byte != None and byte != end: + if byte == '"': + byte = read_byte(f,res) + while byte != None and byte != '"': + if byte == '\\': # Escaped, so just read it without interpretation + read_byte(f,res) + byte = read_byte(f,res) + byte = read_byte(f,res) + elif byte.isspace(): + byte = read_byte(f,res) + elif byte == ';': + byte = read_byte(f,res) + while byte != None and byte != '\n': + byte = read_byte(f,res) + elif byte == '(': + _read_over_files(f, res, ')') + byte = read_byte(f,res) + else: # Assume identifier + identifier = [] + while byte != None and not byte.isspace() and byte != '(' and byte != ')' and byte != ';' and byte != '"': + identifier.extend(byte) + byte = read_byte(f,res) + if first_identifier and ''.join(identifier) == 'files': + # Skip until end of list + _read_over_files(f, [], ')') + raise FoundFiles(res) + + first_identifier = False + return res + +def update_meta(ui, repo): + '''Update the FILES entry in an egg's meta-file. + + Only version-controlled files are added.''' + + meta_file = _find_egg_info_file(repo, 'meta') + files = repo.status(clean=True)[6:][0] + files.remove('.hgtags') + + # A list without the parens around it + files_list = ' '.join(map(_to_scheme_string, files)) + + mf = repo.wfile(meta_file, 'rb') + try: + s = ''.join(_read_over_files(mf, [])) + s = s.rstrip() # Assuming no trailing comments... + s = s[:len(s)-1] + '\n (files ' + files_list + '))\n' + except FoundFiles, value: + s = ''.join(value.res) + files_list + ')' + s += mf.read() # the rest of the file + mf.close + + # reopen and write out the new string + mf = repo.wfile(meta_file, 'w') + mf.write(s) + mf.close + + # This doesn't work because repo.status operates on a cache or something + #if len(repo.status(match=matchmod.exact('.', '.', [meta_file]))[0]) == 0: + # ui.status(_('Meta-file %s was already up-to-date\n') % meta_file) + #else: + ui.status(_('Meta-file %s is updated\n') % meta_file) + cmdtable = { "eggtag": (eggtag, [('r', 'rev', '', @@ -88,5 +174,8 @@ cmdtable = { ('m', 'message', '', _('use <text> as commit message'), _('TEXT')), ], - "hg eggtag [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...") + "hg eggtag [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME..."), + "update-meta": (update_meta, + [], + "hg update-meta") } |