def status(msg, *args, **kwargs): """Write a status message. args are treated as substitutions for msg. The following keyword arguments are allowed: level : One of DEFAULT, VERBOSE or DEBUG. linebreak: If True a new line is appended to msg (default: True). truncate : Truncate output if larger then term width (default: True). """ global _level level = kwargs.get("level", DEFAULT) if level > _level: return width = termwidth() if args: msg = msg % args if kwargs.get("linebreak", True): msg = "%s%s" % (msg, os.linesep) if level == ERROR: stream = sys.stderr else: stream = sys.stdout if kwargs.get("truncate", True) and level != ERROR: add_newline = msg.endswith("\n") msglines = msg.splitlines() for no, line in enumerate(msglines): if len(line) > width: msglines[no] = line[: width - 3] + "..." msg = os.linesep.join(msglines) if add_newline: msg = "%s%s" % (msg, os.linesep) if isinstance(msg, unicode): msg = msg.encode("utf-8") stream.write(msg) stream.flush()
def pull(repo, source, heads=[], force=False, meta=None): """pull new revisions from Subversion""" assert source.capable('subversion') svn_url = source.svnurl # Split off #rev svn_url, heads, checkout = util.parseurl(svn_url, heads) old_encoding = util.swap_out_encoding() total = None try: have_replay = not repo.ui.configbool('hgsubversion', 'stupid') if not have_replay: repo.ui.note('fetching stupidly...\n') svn = source.svn if meta is None: meta = repo.svnmeta(svn.uuid, svn.subdir) stopat_rev = util.parse_revnum(svn, checkout) if meta.layout == 'auto': meta.layout = meta.layout_from_subversion(svn, (stopat_rev or None)) repo.ui.note('using %s layout\n' % meta.layout) if meta.branch: if meta.layout != 'single': msg = ('branch cannot be specified for Subversion clones using ' 'standard directory layout') raise hgerror.Abort(msg) meta.branchmap['default'] = meta.branch ui = repo.ui start = meta.revmap.lastpulled if start <= 0: # we are initializing a new repository start = util.parse_revnum(svn, repo.ui.config('hgsubversion', 'startrev', 0)) if start > 0: if meta.layout == 'standard': raise hgerror.Abort('non-zero start revisions are only ' 'supported for single-directory clones.') ui.note('starting at revision %d; any prior will be ignored\n' % start) # fetch all revisions *including* the one specified... start -= 1 # anything less than zero makes no sense if start < 0: start = 0 skiprevs = repo.ui.configlist('hgsubversion', 'unsafeskip', '') skiprevs = set(util.parse_revnum(svn, r) for r in skiprevs) oldrevisions = len(meta.revmap) if stopat_rev: total = stopat_rev - start else: total = svn.HEAD - start lastpulled = None lock = meta.repo.lock() try: # start converting revisions firstrun = True for r in svn.revisions(start=start, stop=stopat_rev): if (r.revnum in skiprevs or (r.author is None and r.message == 'This is an empty revision for padding.')): lastpulled = r.revnum continue tbdelta = meta.update_branch_tag_map_for_rev(r) # got a 502? Try more than once! tries = 0 converted = False while not converted: try: msg = meta.getmessage(r).strip() if msg: msg = [s.strip() for s in msg.splitlines() if s][0] if getattr(ui, 'termwidth', False): w = ui.termwidth() else: w = hgutil.termwidth() bits = (r.revnum, r.author, msg) ui.status(('[r%d] %s: %s' % bits)[:w] + '\n') compathacks.progress(ui, 'pull', r.revnum - start, total=total) meta.save_tbdelta(tbdelta) close = pullfuns[have_replay](ui, meta, svn, r, tbdelta, firstrun) meta.committags(r, close) for branch, parent in close.iteritems(): if parent in (None, node.nullid): continue meta.delbranch(branch, parent, r) meta.save() converted = True firstrun = False except svnwrap.SubversionRepoCanNotReplay, e: # pragma: no cover ui.status('%s\n' % e.message) stupidmod.print_your_svn_is_old_message(ui) have_replay = False except svnwrap.SubversionException, e: # pragma: no cover if (e.args[1] == svnwrap.ERR_RA_DAV_REQUEST_FAILED and '502' in str(e) and tries < 3): tries += 1 ui.status('Got a 502, retrying (%s)\n' % tries) else: ui.traceback() raise hgerror.Abort(*e.args)
def pull(repo, source, heads=[], force=False): """pull new revisions from Subversion""" assert source.capable('subversion') svn_url = source.svnurl # Split off #rev svn_url, heads, checkout = util.parseurl(svn_url, heads) old_encoding = util.swap_out_encoding() # TODO implement skipto support skipto_rev = 0 try: stopat_rev = int(checkout or 0) except ValueError: raise hgutil.Abort('unrecognised Subversion revision %s: ' 'only numbers work.' % checkout) have_replay = not repo.ui.configbool('hgsubversion', 'stupid') if have_replay and not callable( delta.svn_txdelta_apply(None, None, None)[0]): #pragma: no cover repo.ui.status('You are using old Subversion SWIG bindings. Replay ' 'will not work until you upgrade to 1.5.0 or newer. ' 'Falling back to a slower method that may be buggier. ' 'Please upgrade, or contribute a patch to use the ' 'ctypes bindings instead of SWIG.\n') have_replay = False elif not have_replay: repo.ui.note('fetching stupidly...\n') # TODO: do credentials specified in the URL still work? svn = svnrepo.svnremoterepo(repo.ui, svn_url).svn meta = repo.svnmeta(svn.uuid, svn.subdir) layout = repo.ui.config('hgsubversion', 'layout', 'auto') if layout == 'auto': rootlist = svn.list_dir('', revision=(stopat_rev or None)) if sum(map(lambda x: x in rootlist, ('branches', 'tags', 'trunk'))): layout = 'standard' else: layout = 'single' repo.ui.setconfig('hgsubversion', 'layout', layout) repo.ui.note('using %s layout\n' % layout) start = max(meta.revmap.seen, skipto_rev) initializing_repo = meta.revmap.seen <= 0 ui = repo.ui if initializing_repo and start > 0: raise hgutil.Abort('Revision skipping at repository initialization ' 'remains unimplemented.') oldrevisions = len(meta.revmap) cnt = 0 if stopat_rev: total = stopat_rev - start else: total = svn.HEAD - start try: try: # start converting revisions for r in svn.revisions(start=start, stop=stopat_rev): if (r.author is None and r.message == 'This is an empty revision for padding.'): continue tbdelta = meta.update_branch_tag_map_for_rev(r) # got a 502? Try more than once! tries = 0 converted = False while not converted: try: msg = '' if r.message: msg = r.message.strip() if not msg: msg = util.default_commit_msg else: msg = [s.strip() for s in msg.splitlines() if s][0] w = hgutil.termwidth() bits = (r.revnum, r.author, msg) cnt += 1 ui.status(('[r%d] %s: %s\n' % bits)[:w]) util.progress(ui, 'pull', cnt, total=total) meta.save_tbdelta(tbdelta) close = pullfuns[have_replay](ui, meta, svn, r, tbdelta) meta.committags(r, close) for branch, parent in close.iteritems(): if parent in (None, node.nullid): continue meta.delbranch(branch, parent, r) meta.save() converted = True except svnwrap.SubversionRepoCanNotReplay, e: #pragma: no cover ui.status('%s\n' % e.message) stupidmod.print_your_svn_is_old_message(ui) have_replay = False except core.SubversionException, e: #pragma: no cover if (e.apr_err == core.SVN_ERR_RA_DAV_REQUEST_FAILED and '502' in str(e) and tries < 3): tries += 1 ui.status('Got a 502, retrying (%s)\n' % tries) else: raise hgutil.Abort(*e.args)
def pull(repo, source, heads=[], force=False): """pull new revisions from Subversion""" assert source.capable('subversion') svn_url = source.svnurl # Split off #rev svn_url, heads, checkout = util.parseurl(svn_url, heads) old_encoding = util.swap_out_encoding() try: stopat_rev = int(checkout or 0) except ValueError: raise hgutil.Abort('unrecognised Subversion revision %s: ' 'only numbers work.' % checkout) have_replay = not repo.ui.configbool('hgsubversion', 'stupid') if not have_replay: repo.ui.note('fetching stupidly...\n') svn = source.svn meta = repo.svnmeta(svn.uuid, svn.subdir) layout = repo.ui.config('hgsubversion', 'layout', 'auto') if layout == 'auto': rootlist = svn.list_dir('', revision=(stopat_rev or None)) if sum(map(lambda x: x in rootlist, ('branches', 'tags', 'trunk'))): layout = 'standard' else: layout = 'single' repo.ui.setconfig('hgsubversion', 'layout', layout) repo.ui.note('using %s layout\n' % layout) branch = repo.ui.config('hgsubversion', 'branch') if branch: if layout != 'single': msg = ('branch cannot be specified for Subversion clones using ' 'standard directory layout') raise hgutil.Abort(msg) meta.branchmap['default'] = branch ui = repo.ui start = meta.revmap.youngest origrevcount = len(meta.revmap) if start <= 0: # we are initializing a new repository start = repo.ui.config('hgsubversion', 'startrev', 0) if isinstance(start, str) and start.upper() == 'HEAD': start = svn.last_changed_rev else: start = int(start) if start > 0: if layout == 'standard': raise hgutil.Abort('non-zero start revisions are only ' 'supported for single-directory clones.') ui.note('starting at revision %d; any prior will be ignored\n' % start) # fetch all revisions *including* the one specified... start -= 1 # anything less than zero makes no sense if start < 0: start = 0 oldrevisions = len(meta.revmap) if stopat_rev: total = stopat_rev - start else: total = svn.HEAD - start try: try: # start converting revisions firstrun = True for r in svn.revisions(start=start, stop=stopat_rev): if (r.author is None and r.message == 'This is an empty revision for padding.'): continue tbdelta = meta.update_branch_tag_map_for_rev(r) # got a 502? Try more than once! tries = 0 converted = False while not converted: try: msg = '' if r.message: msg = r.message.strip() if not msg: msg = util.default_commit_msg(ui) else: msg = [s.strip() for s in msg.splitlines() if s][0] if getattr(ui, 'termwidth', False): w = ui.termwidth() else: w = hgutil.termwidth() bits = (r.revnum, r.author, msg) ui.status(('[r%d] %s: %s' % bits)[:w] + '\n') util.progress(ui, 'pull', r.revnum - start, total=total) meta.save_tbdelta(tbdelta) close = pullfuns[have_replay](ui, meta, svn, r, tbdelta, firstrun) meta.committags(r, close) for branch, parent in close.iteritems(): if parent in (None, node.nullid): continue meta.delbranch(branch, parent, r) meta.save() converted = True firstrun = False except svnwrap.SubversionRepoCanNotReplay, e: #pragma: no cover ui.status('%s\n' % e.message) stupidmod.print_your_svn_is_old_message(ui) have_replay = False except svnwrap.SubversionException, e: #pragma: no cover if (e.args[1] == svnwrap.ERR_RA_DAV_REQUEST_FAILED and '502' in str(e) and tries < 3): tries += 1 ui.status('Got a 502, retrying (%s)\n' % tries) else: ui.traceback() raise hgutil.Abort(*e.args)
def width(self): tw = util.termwidth() return min(int(self.ui.config('progress', 'width', default=tw)), tw)
def churn(ui, repo, *pats, **opts): '''histogram of changes to the repository This command will display a histogram representing the number of changed lines or revisions, grouped according to the given template. The default template will group changes by author. The --dateformat option may be used to group the results by date instead. Statistics are based on the number of changed lines, or alternatively the number of matching revisions if the --changesets option is specified. Examples:: # display count of changed lines for every committer hg churn -t '{author|email}' # display daily activity graph hg churn -f '%H' -s -c # display activity of developers by month hg churn -f '%Y-%m' -s -c # display count of lines changed in every year hg churn -f '%Y' -s It is possible to map alternate email addresses to a main address by providing a file using the following format:: <alias email> <actual email> Such a file may be specified with the --aliases option, otherwise a .hgchurn file will be looked for in the working directory root. ''' def pad(s, l): return (s + " " * l)[:l] amap = {} aliases = opts.get('aliases') if not aliases and os.path.exists(repo.wjoin('.hgchurn')): aliases = repo.wjoin('.hgchurn') if aliases: for l in open(aliases, "r"): l = l.strip() alias, actual = l.split() amap[alias] = actual rate = countrate(ui, repo, amap, *pats, **opts).items() if not rate: return sortkey = ((not opts.get('sort')) and (lambda x: -sum(x[1])) or None) rate.sort(key=sortkey) # Be careful not to have a zero maxcount (issue833) maxcount = float(max(sum(v) for k, v in rate)) or 1.0 maxname = max(len(k) for k, v in rate) ttywidth = util.termwidth() ui.debug("assuming %i character terminal\n" % ttywidth) width = ttywidth - maxname - 2 - 2 - 2 if opts.get('diffstat'): width -= 15 def format(name, (added, removed)): return "%s %15s %s%s\n" % (pad(name, maxname), '+%d/-%d' % (added, removed), '+' * charnum(added), '-' * charnum(removed))
def churn(ui, repo, *pats, **opts): '''histogram of changes to the repository This command will display a histogram representing the number of changed lines or revisions, grouped according to the given template. The default template will group changes by author. The --dateformat option may be used to group the results by date instead. Statistics are based on the number of changed lines, or alternatively the number of matching revisions if the --changesets option is specified. Examples: # display count of changed lines for every committer hg churn -t '{author|email}' # display daily activity graph hg churn -f '%H' -s -c # display activity of developers by month hg churn -f '%Y-%m' -s -c # display count of lines changed in every year hg churn -f '%Y' -s It is possible to map alternate email addresses to a main address by providing a file using the following format: <alias email> <actual email> Such a file may be specified with the --aliases option, otherwise a .hgchurn file will be looked for in the working directory root. ''' def pad(s, l): return (s + " " * l)[:l] amap = {} aliases = opts.get('aliases') if not aliases and os.path.exists(repo.wjoin('.hgchurn')): aliases = repo.wjoin('.hgchurn') if aliases: for l in open(aliases, "r"): l = l.strip() alias, actual = l.split() amap[alias] = actual rate = countrate(ui, repo, amap, *pats, **opts).items() if not rate: return sortfn = ((not opts.get('sort')) and (lambda a, b: cmp(b[1], a[1])) or None) rate.sort(sortfn) maxcount = float(max([v for k, v in rate])) maxname = max([len(k) for k, v in rate]) ttywidth = util.termwidth() ui.debug(_("assuming %i character terminal\n") % ttywidth) width = ttywidth - maxname - 2 - 6 - 2 - 2 for date, count in rate: print "%s %6d %s" % (pad( date, maxname), count, "*" * int(count * width / maxcount))
def churn(ui, repo, *pats, **opts): '''histogram of changes to the repository This command will display a histogram representing the number of changed lines or revisions, grouped according to the given template. The default template will group changes by author. The --dateformat option may be used to group the results by date instead. Statistics are based on the number of changed lines, or alternatively the number of matching revisions if the --changesets option is specified. Examples: # display count of changed lines for every committer hg churn -t '{author|email}' # display daily activity graph hg churn -f '%H' -s -c # display activity of developers by month hg churn -f '%Y-%m' -s -c # display count of lines changed in every year hg churn -f '%Y' -s It is possible to map alternate email addresses to a main address by providing a file using the following format: <alias email> <actual email> Such a file may be specified with the --aliases option, otherwise a .hgchurn file will be looked for in the working directory root. ''' def pad(s, l): return (s + " " * l)[:l] amap = {} aliases = opts.get('aliases') if not aliases and os.path.exists(repo.wjoin('.hgchurn')): aliases = repo.wjoin('.hgchurn') if aliases: for l in open(aliases, "r"): l = l.strip() alias, actual = l.split() amap[alias] = actual rate = countrate(ui, repo, amap, *pats, **opts).items() if not rate: return sortfn = ((not opts.get('sort')) and (lambda a, b: cmp(b[1], a[1])) or None) rate.sort(sortfn) maxcount = float(max([v for k, v in rate])) maxname = max([len(k) for k, v in rate]) ttywidth = util.termwidth() ui.debug(_("assuming %i character terminal\n") % ttywidth) width = ttywidth - maxname - 2 - 6 - 2 - 2 for date, count in rate: print "%s %6d %s" % (pad(date, maxname), count, "*" * int(count * width / maxcount))