Merge "repo: Repo does not always handle '.' parameter correctly"
diff --git a/.gitattributes b/.gitattributes
index d65028a..cdd8546 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,4 +1,4 @@
 # Prevent /bin/sh scripts from being clobbered by autocrlf=true
 git_ssh text eol=lf
-main.py text eol=lf
 repo text eol=lf
+hooks/* text eol=lf
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..f070b49
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,8 @@
+Anthony Newnam <anthony.newnam@garmin.com>    Anthony <anthony@bnovc.com>
+Shawn Pearce <sop@google.com>                 Shawn O. Pearce <sop@google.com>
+Jia Bi <bijia@xiaomi.com>                     bijia <bijia@xiaomi.com>
+JoonCheol Park <jooncheol@gmail.com>          Jooncheol Park <jooncheol@gmail.com>
+Sergii Pylypenko <x.pelya.x@gmail.com>        pelya <x.pelya.x@gmail.com>
+Ulrik Sjölin <ulrik.sjolin@sonyericsson.com>  Ulrik Sjolin <ulrik.sjolin@gmail.com>
+Ulrik Sjölin <ulrik.sjolin@sonyericsson.com>  Ulrik Sjolin <ulrik.sjolin@sonyericsson.com>
+Ulrik Sjölin <ulrik.sjolin@sonyericsson.com>  Ulrik Sjölin <ulrik.sjolin@sonyericsson.com>
diff --git a/.pylintrc b/.pylintrc
index c6be743..413d66a 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -53,7 +53,7 @@
 enable=RP0004
 
 # Disable the message(s) with the given id(s).
-disable=R0903,R0912,R0913,R0914,R0915,W0141,C0111,C0103,W0603,W0703,R0911,C0301,C0302,R0902,R0904,W0142,W0212,E1101,E1103,R0201,W0201,W0122,W0232,RP0001,RP0003,RP0101,RP0002,RP0401,RP0701,RP0801,F0401,E0611,R0801,I0011
+disable=C0326,R0903,R0912,R0913,R0914,R0915,W0141,C0111,C0103,W0603,W0703,R0911,C0301,C0302,R0902,R0904,W0142,W0212,E1101,E1103,R0201,W0201,W0122,W0232,RP0001,RP0003,RP0101,RP0002,RP0401,RP0701,RP0801,F0401,E0611,R0801,I0011
 
 [REPORTS]
 
diff --git a/docs/manifest-format.txt b/docs/manifest-format.txt
index 140a782..8fd9137 100644
--- a/docs/manifest-format.txt
+++ b/docs/manifest-format.txt
@@ -175,7 +175,8 @@
   GetApprovedManifest(branch, target)
 
 Return a manifest in which each project is pegged to a known good revision
-for the current branch and target.
+for the current branch and target. This is used by repo sync when the
+--smart-sync option is given.
 
 The target to use is defined by environment variables TARGET_PRODUCT
 and TARGET_BUILD_VARIANT. These variables are used to create a string
@@ -187,7 +188,8 @@
   GetManifest(tag)
 
 Return a manifest in which each project is pegged to the revision at
-the specified tag.
+the specified tag. This is used by repo sync when the --smart-tag option
+is given.
 
 
 Element project
diff --git a/gitc_utils.py b/gitc_utils.py
index 0f3e181..7a35e7a 100644
--- a/gitc_utils.py
+++ b/gitc_utils.py
@@ -24,6 +24,8 @@
 import git_config
 import wrapper
 
+from error import ManifestParseError
+
 NUM_BATCH_RETRIEVE_REVISIONID = 300
 
 def get_gitc_manifest_dir():
@@ -54,7 +56,11 @@
     if gitcmd.Wait():
       print('FATAL: Failed to retrieve revisionExpr for %s' % proj)
       sys.exit(1)
-    proj.revisionExpr = gitcmd.stdout.split('\t')[0]
+    revisionExpr = gitcmd.stdout.split('\t')[0]
+    if not revisionExpr:
+      raise(ManifestParseError('Invalid SHA-1 revision project %s (%s)' %
+                               (proj.remote.url, proj.revisionExpr)))
+    proj.revisionExpr = revisionExpr
 
 def _manifest_groups(manifest):
   """Returns the manifest group string that should be synced
@@ -127,7 +133,7 @@
         repo_proj.revisionExpr = None
 
   # Convert URLs from relative to absolute.
-  for name, remote in manifest.remotes.iteritems():
+  for _name, remote in manifest.remotes.iteritems():
     remote.fetchUrl = remote.resolvedFetchUrl
 
   # Save the manifest.
diff --git a/main.py b/main.py
index 4f4eb9f..c5f1e9c 100755
--- a/main.py
+++ b/main.py
@@ -379,7 +379,7 @@
     self.context = None
     self.handler_order = urllib.request.BaseHandler.handler_order - 50
 
-  def http_error_401(self, req, fp, code, msg, headers):
+  def http_error_401(self, req, fp, code, msg, headers): # pylint:disable=unused-argument
     host = req.get_host()
     retry = self.http_error_auth_reqed('www-authenticate', host, req, headers)
     return retry
diff --git a/manifest_xml.py b/manifest_xml.py
index 3ac607e..295493d 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -102,7 +102,10 @@
     remoteName = self.name
     if self.remoteAlias:
       remoteName = self.remoteAlias
-    return RemoteSpec(remoteName, url, self.reviewUrl)
+    return RemoteSpec(remoteName,
+                      url=url,
+                      review=self.reviewUrl,
+                      orig_name=self.name)
 
 class XmlManifest(object):
   """manages the repo configuration file"""
@@ -249,9 +252,9 @@
         e.setAttribute('path', relpath)
       remoteName = None
       if d.remote:
-        remoteName = d.remote.remoteAlias or d.remote.name
-      if not d.remote or p.remote.name != remoteName:
-        remoteName = p.remote.name
+        remoteName = d.remote.name
+      if not d.remote or p.remote.orig_name != remoteName:
+        remoteName = p.remote.orig_name
         e.setAttribute('remote', remoteName)
       if peg_rev:
         if self.IsMirror:
@@ -267,7 +270,7 @@
             # isn't our value
             e.setAttribute('upstream', p.revisionExpr)
       else:
-        revision = self.remotes[remoteName].revision or d.revisionExpr
+        revision = self.remotes[p.remote.orig_name].revision or d.revisionExpr
         if not revision or revision != p.revisionExpr:
           e.setAttribute('revision', p.revisionExpr)
         if p.upstream and p.upstream != p.revisionExpr:
@@ -969,5 +972,5 @@
   def _output_manifest_project_extras(self, p, e):
     """Output GITC Specific Project attributes"""
     if p.old_revision:
-        e.setAttribute('old-revision', str(p.old_revision))
+      e.setAttribute('old-revision', str(p.old_revision))
 
diff --git a/project.py b/project.py
index 4a601f8..918ee09 100644
--- a/project.py
+++ b/project.py
@@ -315,11 +315,13 @@
                name,
                url=None,
                review=None,
-               revision=None):
+               revision=None,
+               orig_name=None):
     self.name = name
     self.url = url
     self.review = review
     self.revision = revision
+    self.orig_name = orig_name
 
 
 class RepoHook(object):
@@ -1858,7 +1860,10 @@
         #   will fail.
         # * otherwise, fetch all branches to make sure we end up with the
         #   specific commit.
-        current_branch_only = self.upstream and not ID_RE.match(self.upstream)
+        if self.upstream:
+          current_branch_only = not ID_RE.match(self.upstream)
+        else:
+          current_branch_only = False
 
     if not name:
       name = self.remote.name
@@ -2437,7 +2442,7 @@
   def _allrefs(self):
     return self.bare_ref.all
 
-  def _getLogs(self, rev1, rev2, oneline=False, color=True):
+  def _getLogs(self, rev1, rev2, oneline=False, color=True, pretty_format=None):
     """Get logs between two revisions of this project."""
     comp = '..'
     if rev1:
@@ -2448,6 +2453,8 @@
       out = DiffColoring(self.config)
       if out.is_on and color:
         cmd.append('--color')
+      if pretty_format is not None:
+        cmd.append('--pretty=format:%s' % pretty_format)
       if oneline:
         cmd.append('--oneline')
 
@@ -2464,14 +2471,17 @@
           raise
     return None
 
-  def getAddedAndRemovedLogs(self, toProject, oneline=False, color=True):
+  def getAddedAndRemovedLogs(self, toProject, oneline=False, color=True,
+                             pretty_format=None):
     """Get the list of logs from this revision to given revisionId"""
     logs = {}
     selfId = self.GetRevisionId(self._allrefs)
     toId = toProject.GetRevisionId(toProject._allrefs)
 
-    logs['added'] = self._getLogs(selfId, toId, oneline=oneline, color=color)
-    logs['removed'] = self._getLogs(toId, selfId, oneline=oneline, color=color)
+    logs['added'] = self._getLogs(selfId, toId, oneline=oneline, color=color,
+                                  pretty_format=pretty_format)
+    logs['removed'] = self._getLogs(toId, selfId, oneline=oneline, color=color,
+                                    pretty_format=pretty_format)
     return logs
 
   class _GitGetByExec(object):
diff --git a/subcmds/diffmanifests.py b/subcmds/diffmanifests.py
index 0599868..751a202 100644
--- a/subcmds/diffmanifests.py
+++ b/subcmds/diffmanifests.py
@@ -71,6 +71,10 @@
     p.add_option('--no-color',
                  dest='color', action='store_false', default=True,
                  help='does not display the diff in color.')
+    p.add_option('--pretty-format',
+                 dest='pretty_format', action='store',
+                 metavar='<FORMAT>',
+                 help='print the log using a custom git pretty format string')
 
   def _printRawDiff(self, diff):
     for project in diff['added']:
@@ -92,7 +96,7 @@
                                      otherProject.revisionExpr))
       self.out.nl()
 
-  def _printDiff(self, diff, color=True):
+  def _printDiff(self, diff, color=True, pretty_format=None):
     if diff['added']:
       self.out.nl()
       self.printText('added projects : \n')
@@ -124,7 +128,8 @@
         self.printText(' to ')
         self.printRevision(otherProject.revisionExpr)
         self.out.nl()
-        self._printLogs(project, otherProject, raw=False, color=color)
+        self._printLogs(project, otherProject, raw=False, color=color,
+                        pretty_format=pretty_format)
         self.out.nl()
 
     if diff['unreachable']:
@@ -139,9 +144,13 @@
         self.printText(' not found')
         self.out.nl()
 
-  def _printLogs(self, project, otherProject, raw=False, color=True):
-    logs = project.getAddedAndRemovedLogs(otherProject, oneline=True,
-                                          color=color)
+  def _printLogs(self, project, otherProject, raw=False, color=True,
+                 pretty_format=None):
+
+    logs = project.getAddedAndRemovedLogs(otherProject,
+                                          oneline=(pretty_format is None),
+                                          color=color,
+                                          pretty_format=pretty_format)
     if logs['removed']:
       removedLogs = logs['removed'].split('\n')
       for log in removedLogs:
@@ -192,4 +201,4 @@
     if opt.raw:
       self._printRawDiff(diff)
     else:
-      self._printDiff(diff, color=opt.color)
+      self._printDiff(diff, color=opt.color, pretty_format=opt.pretty_format)
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 4af411c..9124a65 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -242,7 +242,7 @@
     if show_smart:
       p.add_option('-s', '--smart-sync',
                    dest='smart_sync', action='store_true',
-                   help='smart sync using manifest from a known good build')
+                   help='smart sync using manifest from the latest known good build')
       p.add_option('-t', '--smart-tag',
                    dest='smart_tag', action='store',
                    help='smart sync using manifest from a known tag')