mercurial/changegroup.py
changeset 49609 9cac281eb9c0
parent 49284 d44e3c45f0e4
child 49610 35d4c2124073
equal deleted inserted replaced
49608:78ba41878f2e 49609:9cac281eb9c0
   867     ellipses=False,
   867     ellipses=False,
   868     clrevtolocalrev=None,
   868     clrevtolocalrev=None,
   869     fullclnodes=None,
   869     fullclnodes=None,
   870     precomputedellipsis=None,
   870     precomputedellipsis=None,
   871     sidedata_helpers=None,
   871     sidedata_helpers=None,
       
   872     debug_info=None,
   872 ):
   873 ):
   873     """Calculate deltas for a set of revisions.
   874     """Calculate deltas for a set of revisions.
   874 
   875 
   875     Is a generator of ``revisiondelta`` instances.
   876     Is a generator of ``revisiondelta`` instances.
   876 
   877 
   976         nodesorder=nodesorder,
   977         nodesorder=nodesorder,
   977         revisiondata=True,
   978         revisiondata=True,
   978         assumehaveparentrevisions=not ellipses,
   979         assumehaveparentrevisions=not ellipses,
   979         deltamode=deltamode,
   980         deltamode=deltamode,
   980         sidedata_helpers=sidedata_helpers,
   981         sidedata_helpers=sidedata_helpers,
       
   982         debug_info=debug_info,
   981     )
   983     )
   982 
   984 
   983     for i, revision in enumerate(revisions):
   985     for i, revision in enumerate(revisions):
   984         if progress:
   986         if progress:
   985             progress.update(i + 1)
   987             progress.update(i + 1)
   999         revision.linknode = linknode
  1001         revision.linknode = linknode
  1000         yield revision
  1002         yield revision
  1001 
  1003 
  1002     if progress:
  1004     if progress:
  1003         progress.complete()
  1005         progress.complete()
       
  1006 
       
  1007 
       
  1008 def make_debug_info():
       
  1009     """ "build a "new" debug_info dictionnary
       
  1010 
       
  1011     That dictionnary can be used to gather information about the bundle process
       
  1012     """
       
  1013     return {
       
  1014         'revision-total': 0,
       
  1015         'revision-changelog': 0,
       
  1016         'revision-manifest': 0,
       
  1017         'revision-files': 0,
       
  1018         'file-count': 0,
       
  1019         'merge-total': 0,
       
  1020         'available-delta': 0,
       
  1021         'available-full': 0,
       
  1022         'delta-against-prev': 0,
       
  1023         'delta-full': 0,
       
  1024         'delta-against-p1': 0,
       
  1025         'denied-delta-candeltafn': 0,
       
  1026         'denied-base-not-available': 0,
       
  1027         'reused-storage-delta': 0,
       
  1028         'computed-delta': 0,
       
  1029     }
       
  1030 
       
  1031 
       
  1032 def merge_debug_info(base, other):
       
  1033     """merge the debug information from <other> into <base>
       
  1034 
       
  1035     This function can be used to gather lower level information into higher level ones.
       
  1036     """
       
  1037     for key in (
       
  1038         'revision-total',
       
  1039         'revision-changelog',
       
  1040         'revision-manifest',
       
  1041         'revision-files',
       
  1042         'merge-total',
       
  1043         'available-delta',
       
  1044         'available-full',
       
  1045         'delta-against-prev',
       
  1046         'delta-full',
       
  1047         'delta-against-p1',
       
  1048         'denied-delta-candeltafn',
       
  1049         'denied-base-not-available',
       
  1050         'reused-storage-delta',
       
  1051         'computed-delta',
       
  1052     ):
       
  1053         base[key] += other[key]
       
  1054 
       
  1055 
       
  1056 _KEY_PART_WIDTH = 17
       
  1057 
       
  1058 
       
  1059 def _dbg_bdl_line(
       
  1060     ui,
       
  1061     indent,
       
  1062     key,
       
  1063     base_value=None,
       
  1064     percentage_base=None,
       
  1065     percentage_key=None,
       
  1066     percentage_ref=None,
       
  1067     extra=None,
       
  1068 ):
       
  1069     """Print one line of debug_bundle_debug_info"""
       
  1070     line = b"DEBUG-BUNDLING: "
       
  1071     line += b' ' * (2 * indent)
       
  1072     key += b":"
       
  1073     if base_value is not None:
       
  1074         assert len(key) + 1 + (2 * indent) <= _KEY_PART_WIDTH
       
  1075         line += key.ljust(_KEY_PART_WIDTH - (2 * indent))
       
  1076         line += b"%10d" % base_value
       
  1077     else:
       
  1078         line += key
       
  1079 
       
  1080     if percentage_base is not None:
       
  1081         assert base_value is not None
       
  1082         percentage = base_value * 100 // percentage_base
       
  1083         if percentage_key is not None:
       
  1084             line += b" (%d%% of %s %d)" % (
       
  1085                 percentage,
       
  1086                 percentage_key,
       
  1087                 percentage_ref,
       
  1088             )
       
  1089         else:
       
  1090             line += b" (%d%%)" % percentage
       
  1091 
       
  1092     if extra:
       
  1093         line += b" "
       
  1094         line += extra
       
  1095 
       
  1096     line += b'\n'
       
  1097     ui.write_err(line)
       
  1098 
       
  1099 
       
  1100 def display_bundling_debug_info(
       
  1101     ui,
       
  1102     debug_info,
       
  1103     cl_debug_info,
       
  1104     mn_debug_info,
       
  1105     fl_debug_info,
       
  1106 ):
       
  1107     """display debug information gathered during a bundling through `ui`"""
       
  1108     d = debug_info
       
  1109     c = cl_debug_info
       
  1110     m = mn_debug_info
       
  1111     f = fl_debug_info
       
  1112     all_info = [
       
  1113         (b"changelog", b"cl", c),
       
  1114         (b"manifests", b"mn", m),
       
  1115         (b"files", b"fl", f),
       
  1116     ]
       
  1117     _dbg_bdl_line(ui, 0, b'revisions', d['revision-total'])
       
  1118     _dbg_bdl_line(ui, 1, b'changelog', d['revision-changelog'])
       
  1119     _dbg_bdl_line(ui, 1, b'manifest', d['revision-manifest'])
       
  1120     extra = b'(for %d revlogs)' % d['file-count']
       
  1121     _dbg_bdl_line(ui, 1, b'files', d['revision-files'], extra=extra)
       
  1122     if d['merge-total']:
       
  1123         _dbg_bdl_line(ui, 1, b'merge', d['merge-total'], d['revision-total'])
       
  1124     for k, __, v in all_info:
       
  1125         if v['merge-total']:
       
  1126             _dbg_bdl_line(ui, 2, k, v['merge-total'], v['revision-total'])
       
  1127 
       
  1128     _dbg_bdl_line(ui, 0, b'deltas')
       
  1129     _dbg_bdl_line(
       
  1130         ui,
       
  1131         1,
       
  1132         b'from-storage',
       
  1133         d['reused-storage-delta'],
       
  1134         percentage_base=d['available-delta'],
       
  1135         percentage_key=b"available",
       
  1136         percentage_ref=d['available-delta'],
       
  1137     )
       
  1138 
       
  1139     if d['denied-delta-candeltafn']:
       
  1140         _dbg_bdl_line(ui, 2, b'denied-fn', d['denied-delta-candeltafn'])
       
  1141     for __, k, v in all_info:
       
  1142         if v['denied-delta-candeltafn']:
       
  1143             _dbg_bdl_line(ui, 3, k, v['denied-delta-candeltafn'])
       
  1144 
       
  1145     if d['denied-base-not-available']:
       
  1146         _dbg_bdl_line(ui, 2, b'denied-nb', d['denied-base-not-available'])
       
  1147     for k, __, v in all_info:
       
  1148         if v['denied-base-not-available']:
       
  1149             _dbg_bdl_line(ui, 3, k, v['denied-base-not-available'])
       
  1150 
       
  1151     if d['computed-delta']:
       
  1152         _dbg_bdl_line(ui, 1, b'computed', d['computed-delta'])
       
  1153 
       
  1154     if d['available-full']:
       
  1155         _dbg_bdl_line(
       
  1156             ui,
       
  1157             2,
       
  1158             b'full',
       
  1159             d['delta-full'],
       
  1160             percentage_base=d['available-full'],
       
  1161             percentage_key=b"native",
       
  1162             percentage_ref=d['available-full'],
       
  1163         )
       
  1164     for k, __, v in all_info:
       
  1165         if v['available-full']:
       
  1166             _dbg_bdl_line(
       
  1167                 ui,
       
  1168                 3,
       
  1169                 k,
       
  1170                 v['delta-full'],
       
  1171                 percentage_base=v['available-full'],
       
  1172                 percentage_key=b"native",
       
  1173                 percentage_ref=v['available-full'],
       
  1174             )
       
  1175 
       
  1176     if d['delta-against-prev']:
       
  1177         _dbg_bdl_line(ui, 2, b'previous', d['delta-against-prev'])
       
  1178     for k, __, v in all_info:
       
  1179         if v['delta-against-prev']:
       
  1180             _dbg_bdl_line(ui, 3, k, v['delta-against-prev'])
       
  1181 
       
  1182     if d['delta-against-p1']:
       
  1183         _dbg_bdl_line(ui, 2, b'parent-1', d['delta-against-prev'])
       
  1184     for k, __, v in all_info:
       
  1185         if v['delta-against-p1']:
       
  1186             _dbg_bdl_line(ui, 3, k, v['delta-against-p1'])
  1004 
  1187 
  1005 
  1188 
  1006 class cgpacker:
  1189 class cgpacker:
  1007     def __init__(
  1190     def __init__(
  1008         self,
  1191         self,
  1084             self._verbosenote = self._repo.ui.note
  1267             self._verbosenote = self._repo.ui.note
  1085         else:
  1268         else:
  1086             self._verbosenote = lambda s: None
  1269             self._verbosenote = lambda s: None
  1087 
  1270 
  1088     def generate(
  1271     def generate(
  1089         self, commonrevs, clnodes, fastpathlinkrev, source, changelog=True
  1272         self,
       
  1273         commonrevs,
       
  1274         clnodes,
       
  1275         fastpathlinkrev,
       
  1276         source,
       
  1277         changelog=True,
  1090     ):
  1278     ):
  1091         """Yield a sequence of changegroup byte chunks.
  1279         """Yield a sequence of changegroup byte chunks.
  1092         If changelog is False, changelog data won't be added to changegroup
  1280         If changelog is False, changelog data won't be added to changegroup
  1093         """
  1281         """
  1094 
  1282 
       
  1283         debug_info = None
  1095         repo = self._repo
  1284         repo = self._repo
       
  1285         if repo.ui.configbool(b'debug', b'bundling-stats'):
       
  1286             debug_info = make_debug_info()
  1096         cl = repo.changelog
  1287         cl = repo.changelog
  1097 
  1288 
  1098         self._verbosenote(_(b'uncompressed size of bundle content:\n'))
  1289         self._verbosenote(_(b'uncompressed size of bundle content:\n'))
  1099         size = 0
  1290         size = 0
  1100 
  1291 
  1105                 # We're our own remote when stripping, get the no-op helpers
  1296                 # We're our own remote when stripping, get the no-op helpers
  1106                 # TODO a better approach would be for the strip bundle to
  1297                 # TODO a better approach would be for the strip bundle to
  1107                 # correctly advertise its sidedata categories directly.
  1298                 # correctly advertise its sidedata categories directly.
  1108                 remote_sidedata = repo._wanted_sidedata
  1299                 remote_sidedata = repo._wanted_sidedata
  1109             sidedata_helpers = sidedatamod.get_sidedata_helpers(
  1300             sidedata_helpers = sidedatamod.get_sidedata_helpers(
  1110                 repo, remote_sidedata
  1301                 repo,
       
  1302                 remote_sidedata,
  1111             )
  1303             )
  1112 
  1304 
       
  1305         cl_debug_info = None
       
  1306         if debug_info is not None:
       
  1307             cl_debug_info = make_debug_info()
  1113         clstate, deltas = self._generatechangelog(
  1308         clstate, deltas = self._generatechangelog(
  1114             cl,
  1309             cl,
  1115             clnodes,
  1310             clnodes,
  1116             generate=changelog,
  1311             generate=changelog,
  1117             sidedata_helpers=sidedata_helpers,
  1312             sidedata_helpers=sidedata_helpers,
       
  1313             debug_info=cl_debug_info,
  1118         )
  1314         )
  1119         for delta in deltas:
  1315         for delta in deltas:
  1120             for chunk in _revisiondeltatochunks(
  1316             for chunk in _revisiondeltatochunks(
  1121                 self._repo, delta, self._builddeltaheader
  1317                 self._repo, delta, self._builddeltaheader
  1122             ):
  1318             ):
  1124                 yield chunk
  1320                 yield chunk
  1125 
  1321 
  1126         close = closechunk()
  1322         close = closechunk()
  1127         size += len(close)
  1323         size += len(close)
  1128         yield closechunk()
  1324         yield closechunk()
       
  1325         if debug_info is not None:
       
  1326             merge_debug_info(debug_info, cl_debug_info)
       
  1327             debug_info['revision-changelog'] = cl_debug_info['revision-total']
  1129 
  1328 
  1130         self._verbosenote(_(b'%8.i (changelog)\n') % size)
  1329         self._verbosenote(_(b'%8.i (changelog)\n') % size)
  1131 
  1330 
  1132         clrevorder = clstate[b'clrevorder']
  1331         clrevorder = clstate[b'clrevorder']
  1133         manifests = clstate[b'manifests']
  1332         manifests = clstate[b'manifests']
  1134         changedfiles = clstate[b'changedfiles']
  1333         changedfiles = clstate[b'changedfiles']
       
  1334 
       
  1335         if debug_info is not None:
       
  1336             debug_info['file-count'] = len(changedfiles)
  1135 
  1337 
  1136         # We need to make sure that the linkrev in the changegroup refers to
  1338         # We need to make sure that the linkrev in the changegroup refers to
  1137         # the first changeset that introduced the manifest or file revision.
  1339         # the first changeset that introduced the manifest or file revision.
  1138         # The fastpath is usually safer than the slowpath, because the filelogs
  1340         # The fastpath is usually safer than the slowpath, because the filelogs
  1139         # are walked in revlog order.
  1341         # are walked in revlog order.
  1154         fastpathlinkrev = fastpathlinkrev and not scmutil.istreemanifest(repo)
  1356         fastpathlinkrev = fastpathlinkrev and not scmutil.istreemanifest(repo)
  1155 
  1357 
  1156         fnodes = {}  # needed file nodes
  1358         fnodes = {}  # needed file nodes
  1157 
  1359 
  1158         size = 0
  1360         size = 0
       
  1361         mn_debug_info = None
       
  1362         if debug_info is not None:
       
  1363             mn_debug_info = make_debug_info()
  1159         it = self.generatemanifests(
  1364         it = self.generatemanifests(
  1160             commonrevs,
  1365             commonrevs,
  1161             clrevorder,
  1366             clrevorder,
  1162             fastpathlinkrev,
  1367             fastpathlinkrev,
  1163             manifests,
  1368             manifests,
  1164             fnodes,
  1369             fnodes,
  1165             source,
  1370             source,
  1166             clstate[b'clrevtomanifestrev'],
  1371             clstate[b'clrevtomanifestrev'],
  1167             sidedata_helpers=sidedata_helpers,
  1372             sidedata_helpers=sidedata_helpers,
       
  1373             debug_info=mn_debug_info,
  1168         )
  1374         )
  1169 
  1375 
  1170         for tree, deltas in it:
  1376         for tree, deltas in it:
  1171             if tree:
  1377             if tree:
  1172                 assert self.version in (b'03', b'04')
  1378                 assert self.version in (b'03', b'04')
  1183                     yield chunk
  1389                     yield chunk
  1184 
  1390 
  1185             close = closechunk()
  1391             close = closechunk()
  1186             size += len(close)
  1392             size += len(close)
  1187             yield close
  1393             yield close
       
  1394         if debug_info is not None:
       
  1395             merge_debug_info(debug_info, mn_debug_info)
       
  1396             debug_info['revision-manifest'] = mn_debug_info['revision-total']
  1188 
  1397 
  1189         self._verbosenote(_(b'%8.i (manifests)\n') % size)
  1398         self._verbosenote(_(b'%8.i (manifests)\n') % size)
  1190         yield self._manifestsend
  1399         yield self._manifestsend
  1191 
  1400 
  1192         mfdicts = None
  1401         mfdicts = None
  1197             ]
  1406             ]
  1198 
  1407 
  1199         manifests.clear()
  1408         manifests.clear()
  1200         clrevs = {cl.rev(x) for x in clnodes}
  1409         clrevs = {cl.rev(x) for x in clnodes}
  1201 
  1410 
       
  1411         fl_debug_info = None
       
  1412         if debug_info is not None:
       
  1413             fl_debug_info = make_debug_info()
  1202         it = self.generatefiles(
  1414         it = self.generatefiles(
  1203             changedfiles,
  1415             changedfiles,
  1204             commonrevs,
  1416             commonrevs,
  1205             source,
  1417             source,
  1206             mfdicts,
  1418             mfdicts,
  1207             fastpathlinkrev,
  1419             fastpathlinkrev,
  1208             fnodes,
  1420             fnodes,
  1209             clrevs,
  1421             clrevs,
  1210             sidedata_helpers=sidedata_helpers,
  1422             sidedata_helpers=sidedata_helpers,
       
  1423             debug_info=fl_debug_info,
  1211         )
  1424         )
  1212 
  1425 
  1213         for path, deltas in it:
  1426         for path, deltas in it:
  1214             h = _fileheader(path)
  1427             h = _fileheader(path)
  1215             size = len(h)
  1428             size = len(h)
  1228             yield close
  1441             yield close
  1229 
  1442 
  1230             self._verbosenote(_(b'%8.i  %s\n') % (size, path))
  1443             self._verbosenote(_(b'%8.i  %s\n') % (size, path))
  1231 
  1444 
  1232         yield closechunk()
  1445         yield closechunk()
       
  1446         if debug_info is not None:
       
  1447             merge_debug_info(debug_info, fl_debug_info)
       
  1448             debug_info['revision-files'] = fl_debug_info['revision-total']
       
  1449 
       
  1450         if debug_info is not None:
       
  1451             display_bundling_debug_info(
       
  1452                 repo.ui,
       
  1453                 debug_info,
       
  1454                 cl_debug_info,
       
  1455                 mn_debug_info,
       
  1456                 fl_debug_info,
       
  1457             )
  1233 
  1458 
  1234         if clnodes:
  1459         if clnodes:
  1235             repo.hook(b'outgoing', node=hex(clnodes[0]), source=source)
  1460             repo.hook(b'outgoing', node=hex(clnodes[0]), source=source)
  1236 
  1461 
  1237     def _generatechangelog(
  1462     def _generatechangelog(
  1238         self, cl, nodes, generate=True, sidedata_helpers=None
  1463         self,
       
  1464         cl,
       
  1465         nodes,
       
  1466         generate=True,
       
  1467         sidedata_helpers=None,
       
  1468         debug_info=None,
  1239     ):
  1469     ):
  1240         """Generate data for changelog chunks.
  1470         """Generate data for changelog chunks.
  1241 
  1471 
  1242         Returns a 2-tuple of a dict containing state and an iterable of
  1472         Returns a 2-tuple of a dict containing state and an iterable of
  1243         byte chunks. The state will not be fully populated until the
  1473         byte chunks. The state will not be fully populated until the
  1330             topic=_(b'changesets'),
  1560             topic=_(b'changesets'),
  1331             clrevtolocalrev={},
  1561             clrevtolocalrev={},
  1332             fullclnodes=self._fullclnodes,
  1562             fullclnodes=self._fullclnodes,
  1333             precomputedellipsis=self._precomputedellipsis,
  1563             precomputedellipsis=self._precomputedellipsis,
  1334             sidedata_helpers=sidedata_helpers,
  1564             sidedata_helpers=sidedata_helpers,
       
  1565             debug_info=debug_info,
  1335         )
  1566         )
  1336 
  1567 
  1337         return state, gen
  1568         return state, gen
  1338 
  1569 
  1339     def generatemanifests(
  1570     def generatemanifests(
  1344         manifests,
  1575         manifests,
  1345         fnodes,
  1576         fnodes,
  1346         source,
  1577         source,
  1347         clrevtolocalrev,
  1578         clrevtolocalrev,
  1348         sidedata_helpers=None,
  1579         sidedata_helpers=None,
       
  1580         debug_info=None,
  1349     ):
  1581     ):
  1350         """Returns an iterator of changegroup chunks containing manifests.
  1582         """Returns an iterator of changegroup chunks containing manifests.
  1351 
  1583 
  1352         `source` is unused here, but is used by extensions like remotefilelog to
  1584         `source` is unused here, but is used by extensions like remotefilelog to
  1353         change what is sent based in pulls vs pushes, etc.
  1585         change what is sent based in pulls vs pushes, etc.
  1442                 topic=_(b'manifests'),
  1674                 topic=_(b'manifests'),
  1443                 clrevtolocalrev=clrevtolocalrev,
  1675                 clrevtolocalrev=clrevtolocalrev,
  1444                 fullclnodes=self._fullclnodes,
  1676                 fullclnodes=self._fullclnodes,
  1445                 precomputedellipsis=self._precomputedellipsis,
  1677                 precomputedellipsis=self._precomputedellipsis,
  1446                 sidedata_helpers=sidedata_helpers,
  1678                 sidedata_helpers=sidedata_helpers,
       
  1679                 debug_info=debug_info,
  1447             )
  1680             )
  1448 
  1681 
  1449             if not self._oldmatcher.visitdir(store.tree[:-1]):
  1682             if not self._oldmatcher.visitdir(store.tree[:-1]):
  1450                 yield tree, deltas
  1683                 yield tree, deltas
  1451             else:
  1684             else:
  1481         mfdicts,
  1714         mfdicts,
  1482         fastpathlinkrev,
  1715         fastpathlinkrev,
  1483         fnodes,
  1716         fnodes,
  1484         clrevs,
  1717         clrevs,
  1485         sidedata_helpers=None,
  1718         sidedata_helpers=None,
       
  1719         debug_info=None,
  1486     ):
  1720     ):
  1487         changedfiles = [
  1721         changedfiles = [
  1488             f
  1722             f
  1489             for f in changedfiles
  1723             for f in changedfiles
  1490             if self._matcher(f) and not self._oldmatcher(f)
  1724             if self._matcher(f) and not self._oldmatcher(f)
  1576                 ellipses=self._ellipses,
  1810                 ellipses=self._ellipses,
  1577                 clrevtolocalrev=clrevtolocalrev,
  1811                 clrevtolocalrev=clrevtolocalrev,
  1578                 fullclnodes=self._fullclnodes,
  1812                 fullclnodes=self._fullclnodes,
  1579                 precomputedellipsis=self._precomputedellipsis,
  1813                 precomputedellipsis=self._precomputedellipsis,
  1580                 sidedata_helpers=sidedata_helpers,
  1814                 sidedata_helpers=sidedata_helpers,
       
  1815                 debug_info=debug_info,
  1581             )
  1816             )
  1582 
  1817 
  1583             yield fname, deltas
  1818             yield fname, deltas
  1584 
  1819 
  1585         progress.complete()
  1820         progress.complete()
  1865         for node in nodes:
  2100         for node in nodes:
  1866             repo.ui.debug(b"%s\n" % hex(node))
  2101             repo.ui.debug(b"%s\n" % hex(node))
  1867 
  2102 
  1868 
  2103 
  1869 def makechangegroup(
  2104 def makechangegroup(
  1870     repo, outgoing, version, source, fastpath=False, bundlecaps=None
  2105     repo,
       
  2106     outgoing,
       
  2107     version,
       
  2108     source,
       
  2109     fastpath=False,
       
  2110     bundlecaps=None,
  1871 ):
  2111 ):
  1872     cgstream = makestream(
  2112     cgstream = makestream(
  1873         repo,
  2113         repo,
  1874         outgoing,
  2114         outgoing,
  1875         version,
  2115         version,
  1915         repo.filtername is None and heads == sorted(repo.heads())
  2155         repo.filtername is None and heads == sorted(repo.heads())
  1916     )
  2156     )
  1917 
  2157 
  1918     repo.hook(b'preoutgoing', throw=True, source=source)
  2158     repo.hook(b'preoutgoing', throw=True, source=source)
  1919     _changegroupinfo(repo, csets, source)
  2159     _changegroupinfo(repo, csets, source)
  1920     return bundler.generate(commonrevs, csets, fastpathlinkrev, source)
  2160     return bundler.generate(
       
  2161         commonrevs,
       
  2162         csets,
       
  2163         fastpathlinkrev,
       
  2164         source,
       
  2165     )
  1921 
  2166 
  1922 
  2167 
  1923 def _addchangegroupfiles(
  2168 def _addchangegroupfiles(
  1924     repo,
  2169     repo,
  1925     source,
  2170     source,