summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--manifest_xml.py125
-rw-r--r--tests/test_manifest_xml.py57
2 files changed, 127 insertions, 55 deletions
diff --git a/manifest_xml.py b/manifest_xml.py
index fe09f498..edcbadae 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -57,6 +57,60 @@ urllib.parse.uses_netloc.extend([
57 'rpc']) 57 'rpc'])
58 58
59 59
60def XmlBool(node, attr, default=None):
61 """Determine boolean value of |node|'s |attr|.
62
63 Invalid values will issue a non-fatal warning.
64
65 Args:
66 node: XML node whose attributes we access.
67 attr: The attribute to access.
68 default: If the attribute is not set (value is empty), then use this.
69
70 Returns:
71 True if the attribute is a valid string representing true.
72 False if the attribute is a valid string representing false.
73 |default| otherwise.
74 """
75 value = node.getAttribute(attr)
76 s = value.lower()
77 if s == '':
78 return default
79 elif s in {'yes', 'true', '1'}:
80 return True
81 elif s in {'no', 'false', '0'}:
82 return False
83 else:
84 print('warning: manifest: %s="%s": ignoring invalid XML boolean' %
85 (attr, value), file=sys.stderr)
86 return default
87
88
89def XmlInt(node, attr, default=None):
90 """Determine integer value of |node|'s |attr|.
91
92 Args:
93 node: XML node whose attributes we access.
94 attr: The attribute to access.
95 default: If the attribute is not set (value is empty), then use this.
96
97 Returns:
98 The number if the attribute is a valid number.
99
100 Raises:
101 ManifestParseError: The number is invalid.
102 """
103 value = node.getAttribute(attr)
104 if not value:
105 return default
106
107 try:
108 return int(value)
109 except ValueError:
110 raise ManifestParseError('manifest: invalid %s="%s" integer' %
111 (attr, value))
112
113
60class _Default(object): 114class _Default(object):
61 """Project defaults within the manifest.""" 115 """Project defaults within the manifest."""
62 116
@@ -757,29 +811,14 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
757 d.destBranchExpr = node.getAttribute('dest-branch') or None 811 d.destBranchExpr = node.getAttribute('dest-branch') or None
758 d.upstreamExpr = node.getAttribute('upstream') or None 812 d.upstreamExpr = node.getAttribute('upstream') or None
759 813
760 sync_j = node.getAttribute('sync-j') 814 d.sync_j = XmlInt(node, 'sync-j', 1)
761 if sync_j == '' or sync_j is None: 815 if d.sync_j <= 0:
762 d.sync_j = 1 816 raise ManifestParseError('%s: sync-j must be greater than 0, not "%s"' %
763 else: 817 (self.manifestFile, d.sync_j))
764 d.sync_j = int(sync_j)
765
766 sync_c = node.getAttribute('sync-c')
767 if not sync_c:
768 d.sync_c = False
769 else:
770 d.sync_c = sync_c.lower() in ("yes", "true", "1")
771
772 sync_s = node.getAttribute('sync-s')
773 if not sync_s:
774 d.sync_s = False
775 else:
776 d.sync_s = sync_s.lower() in ("yes", "true", "1")
777 818
778 sync_tags = node.getAttribute('sync-tags') 819 d.sync_c = XmlBool(node, 'sync-c', False)
779 if not sync_tags: 820 d.sync_s = XmlBool(node, 'sync-s', False)
780 d.sync_tags = True 821 d.sync_tags = XmlBool(node, 'sync-tags', True)
781 else:
782 d.sync_tags = sync_tags.lower() in ("yes", "true", "1")
783 return d 822 return d
784 823
785 def _ParseNotice(self, node): 824 def _ParseNotice(self, node):
@@ -856,39 +895,15 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
856 raise ManifestParseError("project %s path cannot be absolute in %s" % 895 raise ManifestParseError("project %s path cannot be absolute in %s" %
857 (name, self.manifestFile)) 896 (name, self.manifestFile))
858 897
859 rebase = node.getAttribute('rebase') 898 rebase = XmlBool(node, 'rebase', True)
860 if not rebase: 899 sync_c = XmlBool(node, 'sync-c', False)
861 rebase = True 900 sync_s = XmlBool(node, 'sync-s', self._default.sync_s)
862 else: 901 sync_tags = XmlBool(node, 'sync-tags', self._default.sync_tags)
863 rebase = rebase.lower() in ("yes", "true", "1")
864
865 sync_c = node.getAttribute('sync-c')
866 if not sync_c:
867 sync_c = False
868 else:
869 sync_c = sync_c.lower() in ("yes", "true", "1")
870
871 sync_s = node.getAttribute('sync-s')
872 if not sync_s:
873 sync_s = self._default.sync_s
874 else:
875 sync_s = sync_s.lower() in ("yes", "true", "1")
876
877 sync_tags = node.getAttribute('sync-tags')
878 if not sync_tags:
879 sync_tags = self._default.sync_tags
880 else:
881 sync_tags = sync_tags.lower() in ("yes", "true", "1")
882 902
883 clone_depth = node.getAttribute('clone-depth') 903 clone_depth = XmlInt(node, 'clone-depth')
884 if clone_depth: 904 if clone_depth is not None and clone_depth <= 0:
885 try: 905 raise ManifestParseError('%s: clone-depth must be greater than 0, not "%s"' %
886 clone_depth = int(clone_depth) 906 (self.manifestFile, clone_depth))
887 if clone_depth <= 0:
888 raise ValueError()
889 except ValueError:
890 raise ManifestParseError('invalid clone-depth %s in %s' %
891 (clone_depth, self.manifestFile))
892 907
893 dest_branch = node.getAttribute('dest-branch') or self._default.destBranchExpr 908 dest_branch = node.getAttribute('dest-branch') or self._default.destBranchExpr
894 909
@@ -911,7 +926,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
911 groups.extend(set(default_groups).difference(groups)) 926 groups.extend(set(default_groups).difference(groups))
912 927
913 if self.IsMirror and node.hasAttribute('force-path'): 928 if self.IsMirror and node.hasAttribute('force-path'):
914 if node.getAttribute('force-path').lower() in ("yes", "true", "1"): 929 if XmlBool(node, 'force-path', False):
915 gitdir = os.path.join(self.topdir, '%s.git' % path) 930 gitdir = os.path.join(self.topdir, '%s.git' % path)
916 931
917 project = Project(manifest=self, 932 project = Project(manifest=self,
diff --git a/tests/test_manifest_xml.py b/tests/test_manifest_xml.py
index 1cb72971..aa6cb7df 100644
--- a/tests/test_manifest_xml.py
+++ b/tests/test_manifest_xml.py
@@ -20,6 +20,7 @@ from __future__ import print_function
20 20
21import os 21import os
22import unittest 22import unittest
23import xml.dom.minidom
23 24
24import error 25import error
25import manifest_xml 26import manifest_xml
@@ -89,3 +90,59 @@ class ManifestValidateFilePaths(unittest.TestCase):
89 error.ManifestInvalidPathError, self.check_both, path, 'a') 90 error.ManifestInvalidPathError, self.check_both, path, 'a')
90 self.assertRaises( 91 self.assertRaises(
91 error.ManifestInvalidPathError, self.check_both, 'a', path) 92 error.ManifestInvalidPathError, self.check_both, 'a', path)
93
94
95class ValueTests(unittest.TestCase):
96 """Check utility parsing code."""
97
98 def _get_node(self, text):
99 return xml.dom.minidom.parseString(text).firstChild
100
101 def test_bool_default(self):
102 """Check XmlBool default handling."""
103 node = self._get_node('<node/>')
104 self.assertIsNone(manifest_xml.XmlBool(node, 'a'))
105 self.assertIsNone(manifest_xml.XmlBool(node, 'a', None))
106 self.assertEqual(123, manifest_xml.XmlBool(node, 'a', 123))
107
108 node = self._get_node('<node a=""/>')
109 self.assertIsNone(manifest_xml.XmlBool(node, 'a'))
110
111 def test_bool_invalid(self):
112 """Check XmlBool invalid handling."""
113 node = self._get_node('<node a="moo"/>')
114 self.assertEqual(123, manifest_xml.XmlBool(node, 'a', 123))
115
116 def test_bool_true(self):
117 """Check XmlBool true values."""
118 for value in ('yes', 'true', '1'):
119 node = self._get_node('<node a="%s"/>' % (value,))
120 self.assertTrue(manifest_xml.XmlBool(node, 'a'))
121
122 def test_bool_false(self):
123 """Check XmlBool false values."""
124 for value in ('no', 'false', '0'):
125 node = self._get_node('<node a="%s"/>' % (value,))
126 self.assertFalse(manifest_xml.XmlBool(node, 'a'))
127
128 def test_int_default(self):
129 """Check XmlInt default handling."""
130 node = self._get_node('<node/>')
131 self.assertIsNone(manifest_xml.XmlInt(node, 'a'))
132 self.assertIsNone(manifest_xml.XmlInt(node, 'a', None))
133 self.assertEqual(123, manifest_xml.XmlInt(node, 'a', 123))
134
135 node = self._get_node('<node a=""/>')
136 self.assertIsNone(manifest_xml.XmlInt(node, 'a'))
137
138 def test_int_good(self):
139 """Check XmlInt numeric handling."""
140 for value in (-1, 0, 1, 50000):
141 node = self._get_node('<node a="%s"/>' % (value,))
142 self.assertEqual(value, manifest_xml.XmlInt(node, 'a'))
143
144 def test_int_invalid(self):
145 """Check XmlInt invalid handling."""
146 with self.assertRaises(error.ManifestParseError):
147 node = self._get_node('<node a="xx"/>')
148 manifest_xml.XmlInt(node, 'a')