Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(248)

Unified Diff: status.py

Issue 84943003: chromium-status: automatically linkify usernames/status messages (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/chromium-status
Patch Set: address Vadim's feedback in status.py Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | stylesheets/style.css » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: status.py
diff --git a/status.py b/status.py
index 90f01b2d4baa91afbf50e3662f3eae6fe2f6c5ad..05335cb6b1aa99625da7b315d1222fc0386cd570 100644
--- a/status.py
+++ b/status.py
@@ -24,6 +24,110 @@ ALLOWED_ORIGINS = [
]
+class TextFragment(object):
+ """Simple object to hold text that might be linked"""
+
+ def __init__(self, text, target=None, is_email=False):
+ self.text = text
+ self.target = target
+ self.is_email = is_email
+
+ def __repr__(self):
+ return 'TextFragment({%s->%s})' % (self.text, self.target)
+
+
+class LinkableText(object):
+ """Turns arbitrary text into a set of links"""
+
+ GERRIT_URLS = {
+ 'chrome': 'https://chrome-internal-review.googlesource.com',
+ 'chromium': 'https://chromium-review.googlesource.com',
+ }
+
+ WATERFALL_URLS = {
+ 'chromeos': 'http://chromegw/i/chromeos',
+ 'chromiumos': 'http://build.chromium.org/p/chromiumos',
+ }
+
+ # Automatically linkify known strings for the user.
+ _CONVERTS = []
+
+ @classmethod
+ def register_converter(cls, regex, target, pretty, is_email, flags=re.I):
+ """Register a new conversion for creating links from text"""
+ cls._CONVERTS.append(
+ (re.compile(regex, flags=flags), target, pretty, is_email))
+
+ @classmethod
+ def bootstrap(cls, _app_name):
+ """Add conversions (possibly specific to |app_name| instance)"""
+ # Convert CrOS bug links. Support the forms:
+ # http://crbug.com/1234
+ # http://crosbug.com/1234
+ # crbug/1234
+ # crosbug/p/1234
+ cls.register_converter(
+ # 1 2 3 4 5 6 7
+ r'\b((http://)?((crbug|crosbug)(\.com)?(/(p/)?[0-9]+)))\b',
+ r'http://\4.com\6', r'\1', False)
+
+ # Convert e-mail addresses.
+ cls.register_converter(
+ r'(([-+.a-z0-9_!#$%&*/=?^_`{|}~]+)@[-a-z0-9.]+\.[a-z0-9]+)\b',
+ r'\1', r'\2', True)
+
+ # Convert SHA1's to gerrit links. Assume all external since
+ # there is no sane way to detect it's an internal CL.
+ cls.register_converter(
+ r'\b([0-9a-f]{40})\b',
+ r'%s/#q,\1,n,z' % cls.GERRIT_URLS['chromium'], r'\1', False)
+
+ # Convert public gerrit CL numbers which take the form:
+ # CL:1234
+ cls.register_converter(
+ r'\b(CL:([0-9]+))\b',
+ r'%s/\2' % cls.GERRIT_URLS['chromium'], r'\1', False)
+ # Convert internal gerrit CL numbers which take the form:
+ # CL:*1234
+ cls.register_converter(
+ r'\b(CL:\*([0-9]+))\b',
+ r'%s/\2' % cls.GERRIT_URLS['chrome'], r'\1', False)
+
+ # Match the string:
+ # Automatic: "cbuildbot" on "x86-generic ASAN" from.
+ # Do this for everyone since "cbuildbot" is unique to CrOS.
+ # Otherwise, we'd do it only for chromium |app_name| instances.
+ cls.register_converter(
+ r'("cbuildbot" on "([^"]+ canary)")',
+ r'%s/builders/\2' % cls.WATERFALL_URLS['chromeos'], r'\1', False)
+ cls.register_converter(
+ r'("cbuildbot" on "([^"]+)")',
+ r'%s/builders/\2' % cls.WATERFALL_URLS['chromiumos'], r'\1', False)
+
+ @classmethod
+ def parse(cls, text):
+ """Creates a list of TextFragment objects based on |text|"""
+ if not text:
+ return []
+ for prog, target, pretty_text, is_email in cls._CONVERTS:
+ m = prog.search(text)
+ if m:
+ link = TextFragment(m.expand(pretty_text),
+ target=m.expand(target),
+ is_email=is_email)
+ left_links = cls.parse(text[:m.start()].rstrip())
+ right_links = cls.parse(text[m.end():].lstrip())
+ return left_links + [link] + right_links
+ return [TextFragment(text)]
+
+ def __init__(self, text):
+ self.raw_text = text
+ self.links = self.parse(text.strip())
+
+ def __str__(self):
+ return self.raw_text
+
+
class Status(db.Model):
"""Description for the status table."""
# The username who added this status.
@@ -34,6 +138,14 @@ class Status(db.Model):
message = db.StringProperty(required=True)
@property
+ def username_links(self):
+ return LinkableText(self.username)
+
+ @property
+ def message_links(self):
+ return LinkableText(self.message)
+
+ @property
def general_state(self):
"""Returns a string representing the state that the status message
describes.
@@ -298,3 +410,4 @@ def bootstrap():
# Guarantee that at least one instance exists.
if db.GqlQuery('SELECT __key__ FROM Status').get() is None:
Status(username='none', message='welcome to status').put()
+ LinkableText.bootstrap(BasePage.APP_NAME)
« no previous file with comments | « no previous file | stylesheets/style.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698