Commits

Arne Babenhauserheide  committed a9c5a11 Merge

merge

  • Participants
  • Parent commits 014b8d3, 93bc872

Comments (0)

Files changed (2)

-Should output prefix of newly added bug if possible                               | owner:Michael, open:True, id:1364b6de76f3b532867da63223a45d429ba08a46, time:1277687762.41
-list command reports no such file when bugs dir doesn't exist                     | owner:Michael Diamond, open:False, id:21d24c2b58102a88fa7d6ee78cd190c5b10dafa1, time:1278106675.1
-Need to add bug files automatically                                               | owner:Michael, open:False, id:27e00056bfc988ab41c023b5c0a9db9f5e9fa527, time:1277581398.52
-add version command to report what version of b we're using                       | owner:Michael Diamond, open:False, id:4982d102b75bda27e54c16293350ff561c248921, time:1278106694.44
-Files should be added to mercurial at the end, not the begining of the call       | owner:Michael, open:False, id:6ba1ae74c48a6fd84c5d0698fa8169a28e88b343, time:1277680246.97
-Bugs with no details but a details file should act like there is not details file | owner:Michael, open:False, id:9f771c1b687a119eb8e6f9a8443f2c0dde30776b, time:1277680715.42
-edit doesn't handle editors with spaces properly                                  | owner:Michael, open:True, id:aad16b3f42cade7b71eb1cc92c490f77c7366084, time:1310458238.24
-Calling commands that expect an ID without passing an ID throws an exception      | owner:Michael, open:False, id:d33d694650de726f70ff49003835fe6cc61d8d6d, time:1277687733.59
+Should output prefix of newly added bug if possible                               | owner:Michael, open:True, id:1364b6de76f3b532867da63223a45d429ba08a46, time:1277687762.41
+list command reports no such file when bugs dir doesn't exist                     | owner:Michael Diamond, open:False, id:21d24c2b58102a88fa7d6ee78cd190c5b10dafa1, time:1278106675.1
+Need to add bug files automatically                                               | owner:Michael, open:False, id:27e00056bfc988ab41c023b5c0a9db9f5e9fa527, time:1277581398.52
+missing unicode support                                                           | owner:ArneBab, open:False, id:286b661789a9b4ae60ffd0754888cf43563ce668, time:1306670417.88
+add version command to report what version of b we're using                       | owner:Michael Diamond, open:False, id:4982d102b75bda27e54c16293350ff561c248921, time:1278106694.44
+Files should be added to mercurial at the end, not the begining of the call       | owner:Michael, open:False, id:6ba1ae74c48a6fd84c5d0698fa8169a28e88b343, time:1277680246.97
+Bugs with no details but a details file should act like there is not details file | owner:Michael, open:False, id:9f771c1b687a119eb8e6f9a8443f2c0dde30776b, time:1277680715.42
+edit doesn't handle editors with spaces properly                                  | owner:Michael, open:True, id:aad16b3f42cade7b71eb1cc92c490f77c7366084, time:1310458238.24
+Calling commands that expect an ID without passing an ID throws an exception      | owner:Michael, open:False, id:d33d694650de726f70ff49003835fe6cc61d8d6d, time:1277687733.59
 from datetime import datetime
 from mercurial.i18n import _
 from mercurial import hg,commands
+from codecs import open # unicode support
 
 #
 # Version
 #       
 # Helper Methods - often straight from t
 #
-def _datetime(t = ''):
+def _datetime(t = u''):
     """ Returns a formatted string of the time from a timestamp, or now if t is not set. """
-    if t == '':
+    if t == u'':
         t = datetime.now()
     else:
         t = datetime.fromtimestamp(float(t))
 
 def _truth(str):
     """ Indicates the truth of a string """ 
-    return str == 'True'
+    return str == u'True' or str == u'True'
 
 def _task_from_taskline(taskline):
     """Parse a taskline (from a task file) and return a task.
     
     The task returned will be a dictionary such as:
     
-        { 'id': <hash id>,
-          'text': <summary text>,
+        { u'id': <hash id>,
+          u'text': <summary text>,
            ... other metadata ... }
     
     A taskline can also consist of only summary text, in which case the id
     and other metadata will be generated when the line is read.  This is
     supported to enable editing of the taskfile with a simple text editor.
     """
-    if '|' in taskline:
+    if u'|' in taskline:
         text, _, meta = taskline.partition('|')
-        task = { 'text': text.strip() }
+        task = { u'text': text.strip() }
         for piece in meta.strip().split(','):
             label, data = piece.split(':')
             task[label.strip()] = data.strip()
     else:
         text = taskline.strip()
-        task = { 'id': _hash(text), 'text': text, 'owner': '', 'open': 'True', 'time': time.time() }
+        task = { u'id': _hash(text), u'text': text, u'owner': u'', u'open': u'True', u'time': time.time() }
     return task
 
 def _tasklines_from_tasks(tasks):
     """Parse a list of tasks into tasklines suitable for writing to a file."""
     
     tasklines = []
-    tlen = max(map(lambda t: len(t['text']), tasks)) if tasks else 0
+    tlen = max(map(lambda t: len(t[u'text']), tasks)) if tasks else 0
     
     for task in tasks:
-        meta = [m for m in task.items() if m[0] != 'text']
-        meta_str = ', '.join('%s:%s' % m for m in meta)
-        tasklines.append('%s | %s\n' % (task['text'].ljust(tlen), meta_str))
+        meta = [m for m in task.items() if m[0] != u'text']
+        meta_str = u', '.join(u'%s:%s' % m for m in meta)
+        tasklines.append(u'%s | %s\n' % (task[u'text'].ljust(tlen), meta_str))
     
     return tasklines
 
         for i in range(1, id_len+1):
             """ identifies an empty prefix slot, or a singular collision """
             prefix = id[:i]
-            if (not prefix in pre) or (pre[prefix] != ':' and prefix != pre[prefix]):
+            if (not prefix in pre) or (pre[prefix] != u':' and prefix != pre[prefix]):
                 break
         if prefix in pre:
             """ if there is a collision """
             collide = pre[prefix]
             for j in range(i,id_len+1):
                 if collide[:j] == id[:j]:
-                    pre[id[:j]] = ':'
+                    pre[id[:j]] = u':'
                 else:
                     pre[collide[:j]] = collide
                     pre[id[:j]] = id
             """ no collision, can safely add """
             pre[prefix] = id
     pre = dict(zip(pre.values(),pre.keys()))
-    if ':' in pre:
-        del pre[':']
+    if u':' in pre:
+        del pre[u':']
     return pre
 
 def _describe_print(num,type,owner,filter):
     """ Helper function used by list to describe the data just displayed """
-    typeName = 'open' if type else 'resolved'
-    out = _("Found %s %s bug%s") % (num, typeName, '' if num==1 else 's')
-    if owner != '*':
+    typeName = u'open' if type else u'resolved'
+    out = _("Found %s %s bug%s") % (num, typeName, u'' if num==1 else u's')
+    if owner != u'*':
         out = out+(_(" owned by %s") % ('Nobody' if owner=='' else owner))
-    if filter != '':
+    if filter != u'':
         out = out+_(" whose title contains %s") % filter
     return out
 
         """Initialize by reading the task files, if they exist."""
         self.bugsdir = bugsdir
         self.user = user
-        self.file = 'bugs'
-        self.detailsdir = 'details'
+        self.file = u'bugs'
+        self.detailsdir = u'details'
         self.bugs = {}
-        self.init_details = ("# Lines starting with '#' and sections without content\n# are not displayed by a call to 'details'\n#\n"
+        self.init_details = ("# Lines starting with u'#' and sections without content\n# are not displayed by a call to u'details'\n#\n"
         "[paths]\n# Paths related to this bug.\n# suggested format: REPO_PATH:LINENUMBERS\n\n\n"
         "[details]\n# Additional details\n\n\n"
         "[expected]\n# The expected result\n\n\n"
         if os.path.isdir(path):
             raise InvalidTaskfile
         if os.path.exists(path):
-            tfile = open(path, 'r')
+            tfile = open(path, u'r', encoding="utf-8")
             tlns = tfile.readlines()
             tls = [tl.strip() for tl in tlns if tl]
             tasks = map(_task_from_taskline, tls)
             for task in tasks:
-                self.bugs[task['id']] = task
+                self.bugs[task[u'id']] = task
             tfile.close()
     
     def write(self):
         path = os.path.join(os.path.expanduser(self.bugsdir), self.file)
         if os.path.isdir(path):
             raise InvalidTaskfile
-        tasks = sorted(self.bugs.values(), key=itemgetter('id'))
-        tfile = open(path, 'w')
+        tasks = sorted(self.bugs.values(), key=itemgetter(u'id'))
+        tfile = open(path, u'w', encoding="utf-8")
         for taskline in _tasklines_from_tasks(tasks):
             tfile.write(taskline)
         tfile.close()
     
     def _users_list(self):
         """ Returns a mapping of usernames to the number of open bugs assigned to that user """
-        open = [item['owner'] for item in self.bugs.values() if _truth(item['open'])]
-        closed = [item['owner'] for item in self.bugs.values() if not _truth(item['open'])]
+        open = [item[u'owner'] for item in self.bugs.values() if _truth(item[u'open'])]
+        closed = [item[u'owner'] for item in self.bugs.values() if not _truth(item[u'open'])]
         users = {}
         for user in open:
             if user in users:
             if not user in users:
                 users[user] = 0
         
-        if '' in users:
-            users['Nobody'] = users['']
-            del users['']
+        if u'' in users:
+            users[u'Nobody'] = users[u'']
+            del users[u'']
         return users
     
     def _get_user(self,user,force=False):
         """ Given a user prefix, returns the appropriate username, or fails if
         the correct user cannot be identified.
         
-        'me' is a special username which maps to the username specified when
+        u'me' is a special username which maps to the username specified when
         constructing the BugsDict.
-        'Nobody' (and prefixes of 'Nobody') is a special username which maps
+        u'Nobody' (and prefixes of u'Nobody') is a special username which maps
         internally to the empty string, indicating no assignment.
-        If force is true, the user 'Nobody' is used.  This is unadvisable,
-        avoid forcing the username 'Nobody'.
+        If force is true, the user u'Nobody' is used.  This is unadvisable,
+        avoid forcing the username u'Nobody'.
         
         If force is true, it assumes user is not a prefix and should be
         assumed to exist already.
         """
-        if user == 'me':
+        if user == u'me':
             return self.user
-        if user == 'Nobody':
-            return ''
+        if user == u'Nobody':
+            return u''
         users = self._users_list().keys()
         if not force:
             if not user in users:
                 if len(matched) == 0:
                     raise UnknownUser(user)
                 user = matched[0]
-            if user == 'Nobody': # needed twice, since users can also type a prefix to get it
-                return ''
+            if user == u'Nobody': # needed twice, since users can also type a prefix to get it
+                return u''
         return user
             
     
     def id(self, prefix):
         """ Given a prefix, returns the full id of that bug """
-        return self[prefix]['id']
+        return self[prefix][u'id']
     
     def add(self, text):
         """Adds a bug with no owner to the task list"""
-        task_id = ''
+        task_id = u''
         while True:
             # ensures the id is unique, even if the bug title is the same as another
             task_id = _hash(text+task_id)
             if not task_id in self.bugs:
                 break
-        self.bugs[task_id] = {'id': task_id, 'open': 'True', 'owner': self.user, 'text': text, 'time': time.time()}
+        self.bugs[task_id] = {u'id': task_id, u'open': u'True', u'owner': self.user, u'text': text, u'time': time.time()}
         return _("Added bug %s...") % task_id[:10]
     
     def rename(self, prefix, text):
         """
         task = self[prefix]
         if text.startswith('s/') or text.startswith('/'):
-            text = re.sub('^s?/', '', text).rstrip('/')
+            text = re.sub('^s?/', u'', text).rstrip('/')
             find, _, repl = text.partition('/')
-            text = re.sub(find, repl, task['text'])
+            text = re.sub(find, repl, task[u'text'])
         
-        task['text'] = text
+        task[u'text'] = text
     
     def users(self):
         """ Prints a list of users along with the number of open bugs they have """
 		it will not try to guess, or warn the user."""
         task = self[prefix]
         user = self._get_user(user,force)
-        task['owner'] = user
-        if user == '':
-            user = 'Nobody'
-        return _("Assigned %s: '%s' to %s" % (prefix, task['text'], user))
+        task[u'owner'] = user
+        if user == u'':
+            user = u'Nobody'
+        return _("Assigned %s: u'%s' to %s" % (prefix, task[u'text'], user))
     
     def details(self, prefix):
         """ Provides additional details on the requested bug.
         are not displayed.
         """
         task = self[prefix] # confirms prefix does exist
-        path = self._get_details_path(task['id'])[1]
+        path = self._get_details_path(task[u'id'])[1]
         if os.path.exists(path):
             if os.path.isdir(path):
                 raise InvalidDetailsFile(prefix)
             
-            f = open(path)
+            f = open(path, encoding="utf-8")
             text = f.read()
             f.close()
             
         else:
             text = _('No Details File Found.')
         
-        header = _("Title: %s\nID: %s\n") % (task['text'],task['id'])
-        if task['owner'] != '':
-            header = header + (_("Owned By: %s\n") % task['owner'])
-        header = header + (_("Filed On: %s\n\n") % _datetime(task['time']))
+        header = _("Title: %s\nID: %s\n") % (task[u'text'],task[u'id'])
+        if task[u'owner'] != u'':
+            header = header + (_("Owned By: %s\n") % task[u'owner'])
+        header = header + (_("Filed On: %s\n\n") % _datetime(task[u'time']))
         text = header + text
         
         return text.strip()
     def edit(self, prefix, editor='notepad'):
         """Allows the user to edit the details of the specified bug"""
         task = self[prefix] # confirms prefix does exist
-        path = self._get_details_path(task['id'])[1]
+        path = self._get_details_path(task[u'id'])[1]
         if not os.path.exists(path):
-            self._make_details_file(task['id'])
+            self._make_details_file(task[u'id'])
         subprocess.call([editor, path])
         #subprocess.call()
         #print _timestamp()
         
         If they have a username set, the comment will show who made it."""
         task = self[prefix] # confirms prefix does exist
-        path = self._get_details_path(task['id'])[1]
+        path = self._get_details_path(task[u'id'])[1]
         if not os.path.exists(path):
-            self._make_details_file(task['id'])
+            self._make_details_file(task[u'id'])
         
         comment = _("On: %s\n%s") % (_datetime(),comment)
         
-        if self.user != '':
+        if self.user != u'':
             comment = _("By: %s\n%s") % (self.user,comment)
             
-        f = open(path, "a")
+        f = open(path, "a", encoding="utf-8")
         f.write("\n\n"+comment)
         f.close()
     
     def resolve(self, prefix):
         """Marks a bug as resolved"""
         task = self[prefix]
-        task['open'] = 'False'
+        task[u'open'] = u'False'
     
     def reopen(self, prefix):
         """Reopens a bug that was previously resolved"""
         task = self[prefix]
-        task['open'] = 'True'
+        task[u'open'] = u'True'
     
     def list(self,open=True,owner='*',grep=''):
         """Lists all bugs, applying the given filters"""
         
         prefixes = _prefixes(tasks).items()
         for task_id, prefix in prefixes:
-            tasks[task_id]['prefix'] = prefix
+            tasks[task_id][u'prefix'] = prefix
         
-        if owner != '*':
+        if owner != u'*':
             owner = self._get_user(owner)
         
-        small = [task for task in tasks.values() if _truth(task['open']) == open and (owner == '*' or owner == task['owner']) and grep.lower() in task['text'].lower()]
+        small = [task for task in tasks.values() if _truth(task[u'open']) == open and (owner == u'*' or owner == task[u'owner']) and grep.lower() in task[u'text'].lower()]
         if len(small) > 0:
-            prefs = [len(task['prefix']) for task in small]
+            prefs = [len(task[u'prefix']) for task in small]
             plen = max(prefs)
         else:
             plen = 0
-        out = ''
+        out = u''
         for task in small:
-            out += _('%s - %s\n') % (task['prefix'].ljust(plen),task['text'])
+            out += _('%s - %s\n') % (task[u'prefix'].ljust(plen),task[u'text'])
         return out + _describe_print(len(small),open,owner,grep)
 #
 # Mercurial Extention Operations
 		commands.add(ui,repo,dir)
 		ui.popbuffer()
 
-def cmd(ui,repo,cmd = '',*args,**opts):
+def cmd(ui,repo,cmd = u'',*args,**opts):
     """ Distributed Bug Tracker For Mercurial
     
     List of Commands::
         and assign the bug to the exact username specified, or if the user does not already
         exist in the bugs system, use the -f flag to force the name.
         
-        Use 'me' to assign the bug to the current user,
-        and 'Nobody' to remove its assignment.
+        Use u'me' to assign the bug to the current user,
+        and u'Nobody' to remove its assignment.
         
     details prefix
         Prints the extended details of the specified bug
         
             -r list resolved bugs.
         
-            -o list bugs assigned to owner.  '*' will list all bugs, 'me' will list all bugs assigned to the current user, and 'Nobody' will list all unassigned bugs.
+            -o list bugs assigned to owner.  u'*' will list all bugs, u'me' will list all bugs assigned to the current user, and u'Nobody' will list all unassigned bugs.
         
             -g filter by the search string appearing in the title
         
     version
         Outputs the version number of b being used in this repository
     """
-    text = (' '.join(args)).strip();
-    id = ''
-    subtext = ''
+    unicodeargs = []
+    for arg in args:
+        unicodeargs.append(unicode(arg, encoding="utf-8"))
+    args = unicodeargs
+    text = (u' '.join(args)).strip();
+    id = u''
+    subtext = u''
     if len(args) > 0:
         id = args[0]
     if len(args) > 1:
-        subtext = (' '.join(args[1:])).strip();
+        subtext = (u' '.join(args[1:])).strip();
     
     try:
         bugsdir = ui.config("bugs","dir",".bugs")
         user = ui.config("bugs","user",'')
-        if user == 'hg.user':
+        if user == u'hg.user':
             user = ui.username()
         path = repo.root
-        os.chdir(path)
+        os.chdir(path) 
         bd = BugsDict(bugsdir,user)
-        if cmd == 'add':
-            ui.write(bd.add(text)+'\n')
+        if cmd == u'add':
+            ui.write(bd.add(text).encode("utf-8")+'\n')
             bd.write()
-        elif cmd == 'rename':
+        elif cmd == u'rename':
             bd.rename(id, subtext)
             bd.write()
-        elif cmd == 'users':
-            ui.write(bd.users()+'\n')
-        elif cmd == 'assign':
-            ui.write(bd.assign(id, subtext, opts['force'])+'\n')
+        elif cmd == u'users':
+            ui.write(bd.users().encode("utf-8")+'\n')
+        elif cmd == u'assign':
+            ui.write(bd.assign(id, subtext, opts[u'force']).encode("utf-8")+'\n')
             bd.write()
-        elif cmd == 'details':
-            ui.write(bd.details(id)+'\n')
-        elif cmd == 'edit':
+        elif cmd == u'details':
+            ui.write(bd.details(id).encode("utf-8")+'\n')
+        elif cmd == u'edit':
             bd.edit(id, ui.geteditor())
-        elif cmd == 'comment':
+        elif cmd == u'comment':
             bd.comment(id, subtext)
-        elif cmd == 'resolve':
+        elif cmd == u'resolve':
             bd.resolve(id)
             bd.write()
-        elif cmd == 'reopen':
+        elif cmd == u'reopen':
             bd.reopen(id)
             bd.write()
-        elif cmd == 'list' or cmd == '':
-            ui.write(bd.list(not opts['resolved'], opts['owner'], opts['grep'])+'\n')
-        elif cmd == 'id':
-            ui.write(bd.id(id)+'\n')
-        elif cmd == 'version':
+        elif cmd == u'list' or cmd == u'':
+            ui.write(bd.list(not opts[u'resolved'], opts[u'owner'], opts[u'grep']).encode("utf-8")+'\n')
+        elif cmd == u'id':
+            ui.write(bd.id(id).encode("utf-8")+'\n')
+        elif cmd == u'version':
             ui.write(version+'\n')
         else:
             raise UnknownCommand(cmd)
     except UnknownUser, e:
         ui.warn(_("The provided user - %s - did not match any users in the system.  Use -f to force the creation of a new user.\n") % e.user)
     except UnknownCommand, e:
-        ui.warn(_("No such command '%s'\n") % e.cmd)
+        ui.warn(_("No such command u'%s'\n") % e.cmd)
 
     #open=True,owner='*',grep='',verbose=False,quiet=False):
-cmdtable = {"b|bug|bugs": (cmd,[('f', 'force', False, _('Force this exact username')),
-                           ('r', 'resolved', False, _('List resolved bugs')),
-                           ('o', 'owner', '*', _('Specify an owner to list by')),
-                           ('g', 'grep', '', _('Filter titles by STRING'))],_("cmd [args]"))}
+cmdtable = {"b|bug|bugs": (cmd,[('f', u'force', False, _('Force this exact username')),
+                           ('r', u'resolved', False, _('List resolved bugs')),
+                           ('o', u'owner', u'*', _('Specify an owner to list by')),
+                           ('g', u'grep', u'', _('Filter titles by STRING'))],_("cmd [args]"))}