рджреВрд░рд╕реНрде рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛

рдХрд┐рд╕реА рддрд░рд╣ рдореБрдЭреЗ рджреВрд░рд╕реНрде рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдлрд╛рдЗрд▓реЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рджреЗрдЦрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдереАред рдореИрдВ рдХрд┐рд╕реА рднреА рд╕рдордп рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рдЗрд╕реЗ рдХреНрд▓реЛрди рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ред рдЬреИрд╕рд╛ рдХрд┐ рдЕрдкреЗрдХреНрд╖рд┐рдд рдерд╛, рдЗрдВрдЯрд░рдиреЗрдЯ рдкрд░ рдПрдХ рдЦреЛрдЬ рдиреЗ рдмрд╣реБрдд рд╕рд╛рд░реЗ рдЬрд╡рд╛рдм рджрд┐рдП рдЬреИрд╕реЗ "рдпрд╣ рдЕрд╕рдВрднрд╡ рд╣реИ, рдПрдХ рдХреНрд▓реЛрди рдмрдирд╛рдУред" рдФрд░ рдореБрдЭреЗ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рд▓рд┐рдВрдХ рдореЗрдВ рд╕реНрд░реЛрдд рдХреЛрдб рд╡рд╛рд▓реЗ рдХреБрдЫ рд╕рдВрдЧреНрд░рд╣ рдХреЗ рд▓рд┐рдП рдПрдХ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╣реИред рдЪреВрдВрдХрд┐ "рдХреБрдЫ рд▓рд┐рдВрдХ" рдЗрд╕ рд╕рдВрдЧреНрд░рд╣ рдХреА рд╕рд╛рдордЧреНрд░реА рдХреЗ рд╡рд┐рд╡рд░рдг рдХреЗ рд╕рд╛рде рдкреГрд╖реНрда рдкрд░ рд╣реИ (рдЕрдзрд┐рдХ рд╕рдЯреАрдХ рд░реВрдк рд╕реЗ, рдЗрд╕ рд╕рдВрдЧреНрд░рд╣ рдХреЗ рдЕрддрд┐рд░рд┐рдХреНрдд), рдпрд╣ рдХреЗрд╡рд▓ рдлрд╛рдЗрд▓реЛрдВ рдХреА рд╕реВрдЪреА рдХреА рддреБрд▓рдирд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореБрдЭреЗ рдкрд░реНрдпрд╛рдкреНрдд рд▓рдЧрд╛ред рдХреИрд╕реЗ рд╣реЛ?
рдмреЗрд╢рдХ, рдорд░реНрдХреНрдпреВрд░рд┐рдпрд▓ рд╡рд╕реНрддреБрддрдГ рдХреЛрдИ рджреВрд░рд╕реНрде рднрдВрдбрд╛рд░ рдХреНрд╖рдорддрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдЕрдзрд┐рдХ рд╕рдЯреАрдХ рд░реВрдк рд╕реЗ, рдЖрдк рдкреБрд╢ рдФрд░ рдкреБрд▓ (рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ, рдмрд╛рдж рдХреЗ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдорд╛рдорд▓реЗ рдХреЗ рд░реВрдк рдореЗрдВ рдХреНрд▓реЛрди) рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдХреНрдпрд╛ рдлрд╝рд╛рдЗрд▓ рд╕рд┐рд╕реНрдЯрдо рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд┐рдП рдмрд┐рдирд╛ рдЦреАрдВрдЪрдирд╛ рд╕рдВрднрд╡ рд╣реИ? рдЙрддреНрддрд░: рдпрд╣ рд╕рдВрднрд╡ рд╣реИ, hg incoming рд╣рдореЗрдВ рдпрд╣рд╛рдВ рдорджрдж рдХрд░реЗрдЧреАред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдСрдкрд░реЗрд╢рди рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИ:
  1. рдХрд╣реАрдВ рдПрдХ рдирдпрд╛ рдЦрд╛рд▓реА рднрдВрдбрд╛рд░ рдмрдирд╛рдПрдБред рдПрдХ рдЦрд╛рд▓реА рднрдВрдбрд╛рд░ рдореЗрдВ, рдЖрдк рдХрд┐рд╕реА рднреА рднрдВрдбрд╛рд░ рд╕реЗ pull рд╕рдХрддреЗ рд╣реИрдВред
  2. рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреА рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП hg incoming рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ред рдЪреВрдВрдХрд┐ hg incoming hg log рдХреЗ рд╕рдорд╛рди рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдо рдЗрд╕рдХреЗ рдЖрдЙрдЯрдкреБрдЯ рдХреЛ рдмрджрд▓рдиреЗ рдХреА рд╕рдВрднрд╛рд╡рдирд╛рдУрдВ рдореЗрдВ рд╕реАрдорд┐рдд рдирд╣реАрдВ рд╣реИрдВред рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ, рдЖрдк рдкреНрд░рддреНрдпреЗрдХ рд╕рдВрд╢реЛрдзрди рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рд╕рднреА рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╛ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рд╕реНрд╡рдпрдВ рдХреЛ unified diff рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди (рдмрд╛рдЗрдирд░реА рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рд▓рд┐рдП git рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдХреЗ рд╕рд╛рде) рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╣рдореЗрдВ рдбрд┐рдл рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рд╕рднреА рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рд╕реВрдЪреА рдЙрдкрдпреЛрдЧреА рд╣реИред
  3. рдЪреВрдВрдХрд┐ рд╣рдо рд╕рднреА рд╕рдВрд╢реЛрдзрди рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ, рд╡реИрд╕реЗ, рдЖрдк рдХреГрдиреНрддрдХреЛрдВ рдХреА рд╕реВрдЪреА рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдкреНрд░рддреНрдпреЗрдХ рдкрд░рд┐рд╡рд░реНрддрди рдХреЗ рд▓рд┐рдП рдмрдЪреНрдЪреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВред рдЙрди рдмрдЪреНрдЪреЛрдВ рдХреА рдЕрдиреБрдкрд╕реНрдерд┐рддрд┐ рдЬреЛ рдСрдбрд┐рдЯ рдХреЗ рдкреВрд░реНрд╡рдЬреЛрдВ рдирд╣реАрдВ рд╣реИрдВ, рдлрд╛рдЗрд▓реЛрдВ рдХреА рд╕реВрдЪреА рдЬрд┐рд╕рдореЗрдВ рд╣рдо рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ, рд╣рдореЗрдВ рдкрд░реЗрд╢рд╛рди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред
  4. рдорд░реНрдХреНрдпреВрд░рд┐рдпрд▓ рдореЗрдВ рдПрдХ рд╕рдВрд╢реЛрдзрди рд╣реИ, рдЬреЛ рдЖрд╡рд╢реНрдпрдХ рд░реВрдк рд╕реЗ рдХрд┐рд╕реА рднреА рднрдВрдбрд╛рд░ рдореЗрдВ рдореМрдЬреВрдж рд╣реИ рдФрд░ рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ, рдХреЗрд╡рд▓ рдПрдХ рд╣реА рд╣реИ рдЬреЛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдПрдХ рд╣реА рдорд╛рддрд╛-рдкрд┐рддрд╛ рдирд╣реАрдВ рд╣реИ: -1:0000000000000000000000000000000000000000 ред рдпрд╣ рдПрдХ рдЕрдЪреНрдЫрд╛ рд╢реБрд░реБрдЖрддреА рдмрд┐рдВрджреБ рд╣реИред
    рдЗрд╕ рд╕рдВрд╢реЛрдзрди рдХреЗ рд╕рд╛рде рд╢реБрд░реВ, рд╣рдо рдЕрдиреНрдп рд╕рднреА рд╕рдВрд╢реЛрдзрдиреЛрдВ рдореЗрдВ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рд╕реВрдЪреА рдкрд╛рддреЗ рд╣реИрдВ (рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд╕рдВрд╢реЛрдзрди рдореЗрдВ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рд╕реВрдЪреА рдЬреНрдЮрд╛рдд рд╣реИ: рдпрд╣ рдЦрд╛рд▓реА рд╣реИ)ред рдЗрд╕рдХреЗ рд▓рд┐рдП
    1. рдкреНрд░рддреНрдпреЗрдХ рд╕рдВрд╢реЛрдзрди рдХреЗ рд▓рд┐рдП, рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдПрдХ рдХреЛ рдЫреЛрдбрд╝рдХрд░, рд╣рдо рдкрд╣рд▓реЗ рдорд╛рддрд╛-рдкрд┐рддрд╛ рд╕реЗ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рд▓реЗрддреЗ рд╣реИрдВред рдорд╛рддрд╛-рдкрд┐рддрд╛ рд╕реЗ рдмрдЪреНрдЪреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдВрд╢реЛрдзрди рд▓рд╛рдЧрддред
    2. рдЗрд╕ рд╕реВрдЪреА рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдЬреЛрдбрд╝реЗрдВ (рдЖрдк рдЗрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВрдЧреЗ рдпрджрд┐ рдЖрдк hg incoming --style xml --verbose : paths рдЯреИрдЧ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ paths )ред
    3. рд╣рдо рдЗрд╕ рд╕реВрдЪреА рд╕реЗ рд╣рдЯрд╛рдП рдЧрдП рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рд╕реВрдЪреА рдХреЛ рд╣рдЯрд╛ рджреЗрддреЗ рд╣реИрдВ (рдпрд╣ рдЙрд╕реА рд╕реНрдерд╛рди рдкрд░ рдирд┐рдХрд▓рддрд╛ рд╣реИ)ред

  5. рдЕрдм рд╣рдо рдПрдХ рдРрд╕рд╛ рд╕рдВрд╢реЛрдзрди рдвреВрдВрдврддреЗ рд╣реИрдВ рдЬрд┐рд╕рдореЗрдВ рдПрдХ рднреА рд╡рдВрд╢рдЬ рдирд╣реАрдВ рд╣реИред рдпрд╣ hg incoming --rev revspec рджреНрд╡рд╛рд░рд╛ рдЕрдиреБрд░реЛрдз рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╕рдВрд╢реЛрдзрди рд╣реЛрдЧрд╛ред рдЗрд╕ рд╕рдВрд╢реЛрдзрди рдХреЛ рдкрд╛рдХрд░, рд╣рдо рдЗрд╕рдореЗрдВ рдлрд╛рдЗрд▓реЛрдВ рдХреЛ рд╕реВрдЪреАрдмрджреНрдз рдХрд░реЗрдВрдЧреЗред


рдореИрдВ рдзреНрдпрд╛рди рджреЗрддрд╛ рд╣реВрдВ рдХрд┐ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдкреНрд░рд╛рд░реВрдк рдХреЗ рд╕рд╛рде hg incoming рдЖрдЙрдЯрдкреБрдЯ hg incoming рдХреЛ рдЗрд╕ рддрд░рд╣ рдХреЗ рдСрдкрд░реЗрд╢рди рдХреЗ рд▓рд┐рдП рдЗрд╕реНрддреЗрдорд╛рд▓ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЖрдкрдХреЛ рдпрд╛ рддреЛ {file_adds} , {file_mods} рдФрд░ {file_dels} рд╕рд╛рде рдЕрдкрдирд╛ рдЯреЗрдореНрдкреНрд▓реЗрдЯ рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛, рдпрд╛ рд░реЗрдбреАрдореЗрдб рдПрдХ рд▓реЗрдирд╛ рд╣реЛрдЧрд╛: --style xml ред --template рдпрд╣рд╛рдВ рдЖрдкрдХреА рдорджрдж рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдкреНрд░рд╛рд░реВрдк рдХреЛ рд▓рд┐рдЦрдиреЗ рд╕реЗ XML рдХреЗ рд▓рд┐рдП рд╕реИрдХреНрд╕ рдкрд╛рд░реНрд╕рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдХреЛрдб рдмрд╣реБрдд рдХрдо рд╣реЛ рдЬрд╛рдПрдЧрд╛, рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ --style xml рдХрд╛ --style xml рдХрд░рдирд╛ рдкрд╕рдВрдж рдХрд┐рдпрд╛ред

рджрд░рдЕрд╕рд▓, рдХреЛрдб рд╣реА
 #!/usr/bin/env python # vim: fileencoding=utf-8 from __future__ import unicode_literals, division from xml import sax from subprocess import check_call, Popen, PIPE from shutil import rmtree from tempfile import mkdtemp class MercurialRevision(object): __slots__ = ('rev', 'hex', 'tags', 'bookmarks', 'branch', 'parents', 'children', 'added', 'removed', 'modified', 'copies', 'files',) def __init__(self, rev, hex): self.rev = rev self.hex = hex self.parents = [] self.children = [] self.added = set() self.removed = set() self.modified = set() self.copies = {} self.tags = set() self.bookmarks = set() self.branch = None self.files = set() def __str__(self): return '<revision>'.format(hex=self.hex, rev=self.rev) def __repr__(self): return '{0}({rev!r}, {hex!r})'.format(self.__class__.__name__, hex=self.hex, rev=self.rev) def __hash__(self): return int(self.hex, 16) class MercurialHandler(sax.handler.ContentHandler): def startDocument(self): self.curpath = [] self.currev = None nullrev = MercurialRevision(-1, '0' * 40) self.revisions_rev = {nullrev.rev : nullrev} self.revisions_hex = {nullrev.hex : nullrev} self.tags = {} self.bookmarks = {} self.characters_fun = None self.last_data = None def add_tag(self, tag): self.currev.tags.add(tag) self.tags[tag] = self.currev def add_bookmark(self, bookmark): self.currev.bookmarks.add(bookmark) self.bookmarks[bookmark] = self.currev def characters(self, data): if self.characters_fun: if not self.last_data: self.last_data = data else: self.last_data += data def startElement(self, name, attributes): if name == 'log': assert not self.curpath assert not self.currev elif name == 'logentry': assert self.curpath == ['log'] assert not self.currev self.currev = MercurialRevision(int(attributes['revision']), attributes['node']) else: assert self.currev if name == 'tag': assert self.curpath[-1] == 'logentry' self.characters_fun = self.add_tag elif name == 'bookmark': assert self.curpath[-1] == 'logentry' self.characters_fun = self.add_bookmark elif name == 'parent': assert self.curpath[-1] == 'logentry' self.currev.parents.append(self.revisions_hex[attributes['node']]) elif name == 'branch': assert self.curpath[-1] == 'logentry' self.characters_fun = lambda branch: self.currev.__setattr__('branch', branch) elif name == 'path': assert self.curpath[-1] == 'paths' if attributes['action'] == 'M': self.characters_fun = self.currev.modified.add elif attributes['action'] == 'A': self.characters_fun = self.currev.added.add elif attributes['action'] == 'R': self.characters_fun = self.currev.removed.add elif name == 'copy': assert self.curpath[-1] == 'copies' self.characters_fun = (lambda destination, source=attributes['source']: self.currev.copies.__setitem__(source, destination)) self.curpath.append(name) def endElement(self, name): assert self.curpath or self.curpath[-1] == ['log'] assert self.curpath[-1] == name if name == 'logentry': if not self.currev.parents: self.currev.parents.append(self.revisions_rev[self.currev.rev - 1]) for parent in self.currev.parents: parent.children.append(self.currev) self.revisions_hex[self.currev.hex] = self.currev self.revisions_rev[self.currev.rev] = self.currev self.currev = None if self.last_data is None: if self.characters_fun: self.characters_fun('') else: assert self.characters_fun self.characters_fun(self.last_data) self.characters_fun = None self.last_data = None self.curpath.pop() def export_result(self): heads = {revision for revision in self.revisions_hex.values() if not revision.children or all(child.branch != revision.branch for child in revision.children)} # heads contains the same revisions as `hg heads --closed` tips = {head for head in heads if not head.children} return { 'heads': heads, 'tips': tips, 'tags': self.tags, 'bookmarks': self.bookmarks, 'revisions_hex': self.revisions_hex, 'revisions_rev': self.revisions_rev, 'root': self.revisions_rev[-1], } class MercurialRemoteParser(object): __slots__ = ('parser', 'handler', 'tmpdir') def __init__(self, tmpdir=None): self.parser = sax.make_parser() self.handler = MercurialHandler() self.parser.setContentHandler(self.handler) self.tmpdir = tmpdir or mkdtemp(suffix='.hg') self.init_tmpdir() def init_tmpdir(self): check_call(['hg', 'init', self.tmpdir]) def delete_tmpdir(self): if self.tmpdir and rmtree: rmtree(self.tmpdir) __del__ = delete_tmpdir def __enter__(self): return self def __exit__(self, *args, **kwargs): self.delete_tmpdir() @staticmethod def generate_files(parsing_result): toprocess = [parsing_result['root']] processed = set() while toprocess: revision = toprocess.pop(0) if revision.parents: # Inherit files from the first parent assert not revision.files if revision.parents[0] not in processed: assert toprocess toprocess.append(revision) continue revision.files.update(revision.parents[0].files) # Then apply delta found in log assert not (revision.files & revision.added) revision.files.update(revision.added) assert revision.files >= revision.removed revision.files -= revision.removed assert revision.files >= revision.modified, ( 'Expected to find the following files: ' + ','.join( file for file in revision.modified if not file in revision.files)) processed.add(revision) toprocess.extend(child for child in revision.children if not child in processed and not child in toprocess) assert set(parsing_result['revisions_rev'].values()) == processed return parsing_result def parse_url(self, url, rev_name=None): p = Popen(['hg', '--repository', self.tmpdir, 'incoming', '--style', 'xml', '--verbose', url, ] + (['--rev', rev_name] if rev_name else []), stdout=PIPE) p.stdout.readline() # Skip тАЬcomparing with {url}тАЭ header self.parser.parse(p.stdout) parsing_result = self.handler.export_result() self.generate_files(parsing_result) return parsing_result if __name__ == '__main__': import sys def print_files(revision): for file in revision.files: print file remote_url = sys.argv[1] rev_name = sys.argv[2] with MercurialRemoteParser() as remote_parser: parsing_result = remote_parser.parse_url(remote_url, rev_name=rev_name) assert len(parsing_result['tips']) == 1, 'Found more then one head' print_files(next(iter(parsing_result['tips']))) # vim: tw=100 ft=python ts=4 sts=4 sw=4 </revision> 


рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ: python -O list_hg_files.py bitbucket.org/ZyX_I/aurum tip python -O list_hg_files.py bitbucket.org/ZyX_I/aurum tip ред рджреЛрдиреЛрдВ рддрд░реНрдХ (рджреВрд░рд╕реНрде рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА URL рдФрд░ рд╕рдВрд╢реЛрдзрди рдбрд┐рдЬрд╝рд╛рдЗрдирд░) рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

Source: https://habr.com/ru/post/In197312/


All Articles