def _makerage(ui, repo, **opts): configoverrides = { # Make graphlog shorter. ("experimental", "graphshorten"): "1", # Force use of lines-square renderer, as the user's configuration may # not render properly in a text file. ("experimental", "graph.renderer"): "lines-square", # Reduce the amount of data used for debugnetwork speed tests to # increase the chance they complete within 20s. ("debugnetwork", "speed-test-download-size"): "4M", ("debugnetwork", "speed-test-upload-size"): "1M", } # Override the encoding to "UTF-8" to generate the rage in UTF-8. oldencoding = encoding.encoding oldencodingmode = encoding.encodingmode encoding.encoding = "UTF-8" encoding.encodingmode = "replace" def hgcmd(cmdname, *args, **additional_opts): cmd, opts = cmdutil.getcmdanddefaultopts(cmdname, commands.table) opts.update(additional_opts) _repo = repo if "_repo" in opts: _repo = opts["_repo"] del opts["_repo"] # If we failed to popbuffer for some reason, do not mess up with the # main `ui` object. newui = ui.copy() newui.pushbuffer(error=True, subproc=True) newui._colormode = None def remoteui(orig, src, opts): rui = orig(src, opts) rui._outputui = newui return rui try: with newui.configoverride(configoverrides, "rage"), extensions.wrappedfunction( hg, "remoteui", remoteui): if cmd.norepo: cmd(newui, *args, **opts) else: cmd(newui, _repo, *args, **opts) finally: return newui.popbuffer() basic = [ ("date", lambda: time.ctime()), ("unixname", lambda: encoding.environ.get("LOGNAME")), ("hostname", lambda: socket.gethostname()), ("repo location", lambda: repo.root), ("cwd", lambda: pycompat.getcwd()), ("fstype", lambda: util.getfstype(repo.root)), ("active bookmark", lambda: bookmarks._readactive(repo, repo._bookmarks)), ( "hg version", lambda: __import__("edenscm.mercurial.__version__").mercurial. __version__.version, ), ] def _edenfs_rage(): ragecmd = "edenfsctl rage --stdout" if opts.get("preview"): return shcmd(ragecmd + " --dry-run") return shcmd(ragecmd) detailed = [ ( "disk space usage", lambda: shcmd( "wmic LogicalDisk Where DriveType=3 Get DeviceId,FileSystem,FreeSpace,Size" if pycompat.iswindows else "df -h", check=False, ), ), # smartlog as the user sees it ("hg sl", lambda: hgcmd("smartlog", template="{sl_debug}")), ( "hg debugmetalog -t 'since 2d ago'", lambda: hgcmd("debugmetalog", time_range=["since 2d ago"]), ), ( 'first 20 lines of "hg status"', lambda: "\n".join(hgcmd("status").splitlines()[:20]), ), ( "hg debugmutation -r 'draft() & date(-4)' -t 'since 4d ago'", lambda: hgcmd("debugmutation", rev=["draft() & date(-4)"], time_range=["since 4d ago"]), ), ( "hg bookmarks --list-subscriptions", lambda: hgcmd("bookmarks", list_subscriptions=True), ), ("sigtrace", lambda: readsigtraces(repo)), ( "hg blackbox", lambda: "\n".join( hgcmd("blackbox", pattern=BLACKBOX_PATTERN).splitlines()[-500:] ), ), ("hg summary", lambda: hgcmd("summary")), ("hg cloud status", lambda: hgcmd("cloud status")), ("hg debugprocesstree", lambda: hgcmd("debugprocesstree")), ("hg config (local)", lambda: "\n".join(localconfig(ui))), ("hg sparse", lambda: hgcmd("sparse")), ("hg debugchangelog", lambda: hgcmd("debugchangelog")), ("hg debugexpandpaths", lambda: hgcmd("debugexpandpaths")), ("hg debuginstall", lambda: hgcmd("debuginstall")), ("hg debugdetectissues", lambda: hgcmd("debugdetectissues")), ("usechg", usechginfo), ( "uptime", lambda: shcmd("wmic path Win32_OperatingSystem get LastBootUpTime" if pycompat.iswindows else "uptime"), ), ("rpm info", (partial(rpminfo, ui))), ("klist", lambda: shcmd("klist", check=False)), ("ifconfig", lambda: shcmd("ipconfig" if pycompat.iswindows else "ifconfig")), ( "airport", lambda: shcmd( "/System/Library/PrivateFrameworks/Apple80211." + "framework/Versions/Current/Resources/airport " + "--getinfo", check=False, ), ), ("hg debugnetwork", lambda: hgcmd("debugnetwork")), ("infinitepush backup state", lambda: readinfinitepushbackupstate(repo)), ("commit cloud workspace sync state", lambda: readcommitcloudstate(repo)), ( "infinitepush / commitcloud backup logs", lambda: infinitepushbackuplogs(ui, repo), ), ("scm daemon logs", lambda: scmdaemonlog(ui, repo)), ("debugstatus", lambda: hgcmd("debugstatus")), ("debugtree", lambda: hgcmd("debugtree")), ("hg config (all)", lambda: "\n".join(allconfig(ui))), ("edenfs rage", _edenfs_rage), ( "environment variables", lambda: "\n".join( sorted([ "{}={}".format(k, v) for k, v in encoding.environ.items() ])), ), ("ssh config", lambda: shcmd("ssh -G hg.vip.facebook.com", check=False)), ("debuglocks", lambda: hgcmd("debuglocks")), ("x2pagentd info", lambda: checkproxyagentstate(ui)), ] msg = "" if util.safehasattr(repo, "name"): # Add the contents of both local and shared pack directories. packlocs = { "local": lambda category: shallowutil.getlocalpackpath( repo.svfs.vfs.base, category), "shared": lambda category: shallowutil.getcachepackpath(repo, category), } for loc, getpath in pycompat.iteritems(packlocs): for category in constants.ALL_CATEGORIES: path = getpath(category) detailed.append(( "%s packs (%s)" % (loc, constants.getunits(category)), lambda path=path: "%s:\n%s" % ( path, shcmd("dir /o-s %s" % os.path.normpath(path) if pycompat.iswindows else "ls -lhS %s" % path), ), )) footnotes = [] timeout = opts.get("timeout") or 20 def _failsafe(gen, timeout=timeout): class TimedOut(RuntimeError): pass def target(result, gen): try: result.append(gen()) except TimedOut: return except Exception as ex: index = len(footnotes) + 1 footnotes.append("[%d]: %s\n%s\n\n" % (index, str(ex), traceback.format_exc())) result.append("(Failed. See footnote [%d])" % index) result = [] thread = threading.Thread(target=target, args=(result, gen)) thread.daemon = True thread.start() thread.join(timeout) if result: value = result[0] return value else: if thread.is_alive(): # Attempt to stop the thread, since hg is not thread safe. # There is no pure Python API to interrupt a thread. # But CPython C API can do that. ctypes.pythonapi.PyThreadState_SetAsyncExc( ctypes.c_long(thread.ident), ctypes.py_object(TimedOut)) return ( "(Did not complete in %s seconds, rerun with a larger --timeout to collect this)" % timeout) msg = [] profile = [] allstart = time.time() for name, gen in basic: msg.append("%s: %s\n\n" % (name, _failsafe(gen))) profile.append((time.time() - allstart, "basic info", None)) for name, gen in detailed: start = time.time() with progress.spinner(ui, "collecting %r" % name): value = _failsafe(gen) finish = time.time() msg.append("%s: (%.2f s)\n---------------------------\n%s\n\n" % (name, finish - start, value)) profile.append((finish - start, name, value.count("\n"))) allfinish = time.time() profile.append((allfinish - allstart, "total time", None)) msg.append("hg rage profile:\n") width = max([len(name) for _t, name, _l in profile]) for timetaken, name, lines in reversed(sorted(profile)): m = " %-*s %8.2f s" % (width + 1, name + ":", timetaken) if lines is not None: msg.append("%s for %4d lines\n" % (m, lines)) else: msg.append("%s\n" % m) msg.append("\n") msg.extend(footnotes) msg = "".join(msg) encoding.encoding = oldencoding encoding.encodingmode = oldencodingmode return msg
def _makerage(ui, repo, **opts): # Make graphlog shorter. configoverrides = {("experimental", "graphshorten"): "1"} def hgcmd(cmdname, *args, **additional_opts): cmd, opts = cmdutil.getcmdanddefaultopts(cmdname, commands.table) opts.update(additional_opts) _repo = repo if "_repo" in opts: _repo = opts["_repo"] del opts["_repo"] # If we failed to popbuffer for some reason, do not mess up with the # main `ui` object. newui = ui.copy() newui.pushbuffer(error=True) try: with ui.configoverride(configoverrides, "rage"): if cmd.norepo: cmd(newui, *args, **opts) else: cmd(newui, _repo, *args, **opts) finally: return newui.popbuffer() basic = [ ("date", lambda: time.ctime()), ("unixname", lambda: encoding.environ.get("LOGNAME")), ("hostname", lambda: socket.gethostname()), ("repo location", lambda: repo.root), ("cwd", lambda: pycompat.getcwd()), ("fstype", lambda: util.getfstype(repo.root)), ("active bookmark", lambda: bookmarks._readactive(repo, repo._bookmarks)), ( "hg version", lambda: __import__( "edenscm.mercurial.__version__" ).mercurial.__version__.version, ), ("obsstore size", lambda: str(repo.svfs.stat("obsstore").st_size)), ] oldcolormode = ui._colormode ui._colormode = None detailed = [ ("df -h", lambda: shcmd("df -h", check=False)), # smartlog as the user sees it ("hg sl", lambda: hgcmd("smartlog", template="{sl_debug}")), # unfiltered smartlog for recent hidden changesets, including full # node identity ( "hg sl --master='interestingmaster()' -r 'predecessors(draft())'", lambda: hgcmd( "smartlog", master="interestingmaster()", rev=["predecessors(draft())"], _repo=repo.unfiltered(), template='{sub("\\n", " ", "{node} {sl_debug}")}', ), ), ( 'first 20 lines of "hg status"', lambda: "\n".join(hgcmd("status").splitlines()[:20]), ), ( "hg blackbox", lambda: "\n".join( hgcmd("blackbox", pattern=BLACKBOX_PATTERN).splitlines()[-500:] ), ), ("hg summary", lambda: hgcmd("summary")), ("hg cloud status", lambda: hgcmd("cloud status")), ("hg debugprocesstree", lambda: hgcmd("debugprocesstree")), ("hg config (local)", lambda: "\n".join(localconfig(ui))), ("hg sparse show", lambda: hgcmd("sparse show")), ("hg debuginstall", lambda: hgcmd("debuginstall")), ("usechg", (usechginfo)), ( "uptime", lambda: shcmd( "wmic path Win32_OperatingSystem get LastBootUpTime" if pycompat.iswindows else "uptime" ), ), ("rpm info", (partial(rpminfo, ui))), ("klist", lambda: shcmd("klist", check=False)), ("ifconfig", lambda: shcmd("ipconfig" if pycompat.iswindows else "ifconfig")), ( "airport", lambda: shcmd( "/System/Library/PrivateFrameworks/Apple80211." + "framework/Versions/Current/Resources/airport " + "--getinfo", check=False, ), ), ( 'last 100 lines of "hg debugobsolete"', lambda: "\n".join(hgcmd("debugobsolete").splitlines()[-100:]), ), ("infinitepush backup state", lambda: readinfinitepushbackupstate(repo)), ("commit cloud workspace sync state", lambda: readcommitcloudstate(repo)), ( "infinitepush / commitcloud backup logs", lambda: infinitepushbackuplogs(ui, repo), ), ("scm daemon logs", lambda: scmdaemonlog(ui, repo)), ("debugstatus", lambda: hgcmd("debugstatus")), ("debugtree", lambda: hgcmd("debugtree")), ("hg config (overrides)", lambda: "\n".join(overriddenconfig(ui))), ("edenfs rage", lambda: shcmd("edenfsctl rage --stdout")), ( "environment variables", lambda: "\n".join( sorted(["{}={}".format(k, v) for k, v in encoding.environ.items()]) ), ), ("ssh config", lambda: shcmd("ssh -G hg.vip.facebook.com", check=False)), ] msg = "" if util.safehasattr(repo, "name"): # Add the contents of both local and shared pack directories. packlocs = { "local": lambda category: shallowutil.getlocalpackpath( repo.svfs.vfs.base, category ), "shared": lambda category: shallowutil.getcachepackpath(repo, category), } for loc, getpath in packlocs.iteritems(): for category in constants.ALL_CATEGORIES: path = getpath(category) detailed.append( ( "%s packs (%s)" % (loc, constants.getunits(category)), lambda path=path: "%s:\n%s" % ( path, shcmd( "dir /o-s %s" % os.path.normpath(path) if pycompat.iswindows else "ls -lhS %s" % path ), ), ) ) footnotes = [] timeout = opts.get("timeout") or 20 def _failsafe(gen, timeout=timeout): class TimedOut(RuntimeError): pass def target(result, gen): try: result.append(gen()) except TimedOut: return except Exception as ex: index = len(footnotes) + 1 footnotes.append( "[%d]: %s\n%s\n\n" % (index, str(ex), traceback.format_exc()) ) result.append("(Failed. See footnote [%d])" % index) result = [] thread = threading.Thread(target=target, args=(result, gen)) thread.daemon = True thread.start() thread.join(timeout) if result: value = result[0] return value else: if thread.is_alive(): # Attempt to stop the thread, since hg is not thread safe. # There is no pure Python API to interrupt a thread. # But CPython C API can do that. ctypes.pythonapi.PyThreadState_SetAsyncExc( ctypes.c_long(thread.ident), ctypes.py_object(TimedOut) ) return ( "(Did not complete in %s seconds, rerun with a larger --timeout to collect this)" % timeout ) msg = [] profile = [] allstart = time.time() for name, gen in basic: msg.append("%s: %s\n\n" % (name, _failsafe(gen))) profile.append((time.time() - allstart, "basic info", None)) for name, gen in detailed: start = time.time() with progress.spinner(ui, "collecting %r" % name): value = _failsafe(gen) finish = time.time() msg.append( "%s: (%.2f s)\n---------------------------\n%s\n\n" % (name, finish - start, value) ) profile.append((finish - start, name, value.count("\n"))) allfinish = time.time() profile.append((allfinish - allstart, "total time", None)) msg.append("hg rage profile:\n") width = max([len(name) for _t, name, _l in profile]) for timetaken, name, lines in reversed(sorted(profile)): m = " %-*s %8.2f s" % (width + 1, name + ":", timetaken) if lines is not None: msg.append("%s for %4d lines\n" % (m, lines)) else: msg.append("%s\n" % m) msg.append("\n") msg.extend(footnotes) msg = "".join(msg) ui._colormode = oldcolormode return msg
def _makerage(ui, repo, **opts): configoverrides = { # Make graphlog shorter. ("experimental", "graphshorten"): "1", # Force use of lines-square renderer, as the user's configuration may # not render properly in a text file. ("experimental", "graph.renderer"): "lines-square", # Reduce the amount of data used for debugnetwork speed tests to # increase the chance they complete within 20s. ("debugnetwork", "speed-test-download-size"): "4M", ("debugnetwork", "speed-test-upload-size"): "1M", } # Override the encoding to "UTF-8" to generate the rage in UTF-8. oldencoding = encoding.encoding oldencodingmode = encoding.encodingmode encoding.encoding = "UTF-8" encoding.encodingmode = "replace" def hgcmd(cmdname, *args, **additional_opts): cmdargs = ["hg", *cmdname.split(), *args] for flagname, flagvalue in additional_opts.items(): flagname = flagname.replace("_", "-") if isinstance(flagvalue, list): cmdargs += [f"--{flagname}={v}" for v in flagvalue] else: cmdargs += [f"--{flagname}={flagvalue}"] fin = util.stringio() fout = ferr = util.stringio() status = bindings.commands.run(cmdargs, fin, fout, ferr) output = fout.getvalue().decode() if status != 0: output += f"[{status}]\n" return output basic = [ ("date", lambda: time.ctime()), ("unixname", lambda: encoding.environ.get("LOGNAME")), ("hostname", lambda: socket.gethostname()), ("repo location", lambda: repo.root), ("cwd", lambda: pycompat.getcwd()), ("fstype", lambda: util.getfstype(repo.root)), ("active bookmark", lambda: bookmarks._readactive(repo, repo._bookmarks)), ( "hg version", lambda: __import__( "edenscm.mercurial.__version__" ).mercurial.__version__.version, ), ] def _edenfs_rage(): ragecmd = "edenfsctl rage --stdout" if opts.get("preview"): return shcmd(ragecmd + " --dry-run") return shcmd(ragecmd) detailed = [ ( "disk space usage", lambda: shcmd( "wmic LogicalDisk Where DriveType=3 Get DeviceId,FileSystem,FreeSpace,Size" if pycompat.iswindows else "df -h", check=False, ), ), # smartlog as the user sees it ("hg sl", lambda: hgcmd("smartlog", template="{sl_debug}")), ( "hg debugmetalog -t 'since 2d ago'", lambda: hgcmd("debugmetalog", time_range=["since 2d ago"]), ), ( 'first 20 lines of "hg status"', lambda: "\n".join(hgcmd("status").splitlines()[:20]), ), ( "hg debugmutation -r 'draft() & date(-4)' -t 'since 4d ago'", lambda: hgcmd( "debugmutation", rev=["draft() & date(-4)"], time_range=["since 4d ago"] ), ), ( "hg bookmarks --list-subscriptions", lambda: hgcmd("bookmarks", list_subscriptions=True), ), ("sigtrace", lambda: readsigtraces(repo)), ( "hg blackbox", lambda: "\n".join( hgcmd("blackbox", pattern=BLACKBOX_PATTERN).splitlines()[-500:] ), ), ("hg summary", lambda: hgcmd("summary")), ("hg cloud status", lambda: hgcmd("cloud status")), ("hg debugprocesstree", lambda: hgcmd("debugprocesstree")), ("hg config (local)", lambda: "\n".join(localconfig(ui))), ("hg sparse", lambda: hgcmd("sparse")), ("hg debugchangelog", lambda: hgcmd("debugchangelog")), ("hg debugexpandpaths", lambda: hgcmd("debugexpandpaths")), ("hg debuginstall", lambda: hgcmd("debuginstall")), ("hg debugdetectissues", lambda: hgcmd("debugdetectissues")), ("usechg", usechginfo), ( "uptime", lambda: shcmd( "wmic path Win32_OperatingSystem get LastBootUpTime" if pycompat.iswindows else "uptime" ), ), ("rpm info", (partial(rpminfo, ui))), ("klist", lambda: shcmd("klist", check=False)), ("ifconfig", lambda: shcmd("ipconfig" if pycompat.iswindows else "ifconfig")), ( "airport", lambda: shcmd( "/System/Library/PrivateFrameworks/Apple80211." + "framework/Versions/Current/Resources/airport " + "--getinfo", check=False, ), ), ("hg debugnetwork", lambda: hgcmd("debugnetwork")), ("hg debugnetworkdoctor", lambda: hgcmd("debugnetworkdoctor")), ("infinitepush backup state", lambda: readinfinitepushbackupstate(repo)), ("commit cloud workspace sync state", lambda: readcommitcloudstate(repo)), ( "infinitepush / commitcloud backup logs", lambda: infinitepushbackuplogs(ui, repo), ), ("scm daemon logs", lambda: scmdaemonlog(ui, repo)), ("debugstatus", lambda: hgcmd("debugstatus")), ("debugtree", lambda: hgcmd("debugtree")), ("hg config (all)", lambda: "\n".join(allconfig(ui))), ("edenfs rage", _edenfs_rage), ( "environment variables", lambda: "\n".join( sorted(["{}={}".format(k, v) for k, v in encoding.environ.items()]) ), ), ("ssh config", lambda: shcmd("ssh -G hg.vip.facebook.com", check=False)), ("debuglocks", lambda: hgcmd("debuglocks")), ("x2pagentd info", lambda: checkproxyagentstate(ui)), ("sks-agent rage", lambda: sksagentrage(ui)), ] msg = "" footnotes = [] timeout = opts.get("timeout") or 20 def _failsafe(gen, timeout=timeout): class TimedOut(RuntimeError): pass def target(result, gen): try: result.append(gen()) except TimedOut: return except Exception as ex: index = len(footnotes) + 1 footnotes.append( "[%d]: %s\n%s\n\n" % (index, str(ex), traceback.format_exc()) ) result.append("(Failed. See footnote [%d])" % index) result = [] thread = threading.Thread(target=target, args=(result, gen)) thread.daemon = True thread.start() thread.join(timeout) if result: value = result[0] return value else: if thread.is_alive(): # Attempt to stop the thread, since hg is not thread safe. # There is no pure Python API to interrupt a thread. # But CPython C API can do that. ctypes.pythonapi.PyThreadState_SetAsyncExc( ctypes.c_long(thread.ident), ctypes.py_object(TimedOut) ) return ( "(Did not complete in %s seconds, rerun with a larger --timeout to collect this)" % timeout ) msg = [] profile = [] allstart = time.time() for name, gen in basic: msg.append("%s: %s\n\n" % (name, _failsafe(gen))) profile.append((time.time() - allstart, "basic info", None)) for name, gen in detailed: start = time.time() with progress.spinner(ui, name): value = _failsafe(gen) finish = time.time() msg.append( "%s: (%.2f s)\n---------------------------\n%s\n\n" % (name, finish - start, value) ) profile.append((finish - start, name, value.count("\n"))) allfinish = time.time() profile.append((allfinish - allstart, "total time", None)) msg.append("hg rage profile:\n") width = max([len(name) for _t, name, _l in profile]) for timetaken, name, lines in reversed(sorted(profile)): m = " %-*s %8.2f s" % (width + 1, name + ":", timetaken) if lines is not None: msg.append("%s for %4d lines\n" % (m, lines)) else: msg.append("%s\n" % m) msg.append("\n") msg.extend(footnotes) msg = "".join(msg) encoding.encoding = oldencoding encoding.encodingmode = oldencodingmode return msg