Changeset View
Changeset View
Standalone View
Standalone View
swh/loader/svn/ra.py
Show First 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | |||||
NOEXEC_FLAG = 2 | NOEXEC_FLAG = 2 | ||||
SVN_PROPERTY_EOL = 'svn:eol-style' | SVN_PROPERTY_EOL = 'svn:eol-style' | ||||
# EOL state check mess | # EOL state check mess | ||||
EOL_STYLE = {} | EOL_STYLE = {} | ||||
class SWHFileEditor: | class FileEditor: | ||||
"""File Editor in charge of updating file on disk and memory objects. | """File Editor in charge of updating file on disk and memory objects. | ||||
""" | """ | ||||
__slots__ = ['directory', 'path', 'fullpath', 'executable', 'link'] | __slots__ = ['directory', 'path', 'fullpath', 'executable', 'link'] | ||||
def __init__(self, directory, rootpath, path): | def __init__(self, directory, rootpath, path): | ||||
self.directory = directory | self.directory = directory | ||||
self.path = path | self.path = path | ||||
▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | def close(self): | ||||
mode = os.lstat(self.fullpath).st_mode | mode = os.lstat(self.fullpath).st_mode | ||||
self.directory[self.path] = Content.from_bytes(mode=mode, | self.directory[self.path] = Content.from_bytes(mode=mode, | ||||
data=data) | data=data) | ||||
else: | else: | ||||
self.directory[self.path] = Content.from_file(path=self.fullpath, | self.directory[self.path] = Content.from_file(path=self.fullpath, | ||||
data=True) | data=True) | ||||
class BaseDirSWHEditor: | class BaseDirEditor: | ||||
"""Base class implementation of dir editor. | """Base class implementation of dir editor. | ||||
see :class:`SWHDirEditor` for an implementation that hashes every | see :class:`DirEditor` for an implementation that hashes every | ||||
directory encountered. | directory encountered. | ||||
Instantiate a new class inheriting from this class and define the following | Instantiate a new class inheriting from this class and define the following | ||||
functions:: | functions:: | ||||
def update_checksum(self): | def update_checksum(self): | ||||
# Compute the checksums at current state | # Compute the checksums at current state | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | def add_directory(self, *args): | ||||
raise NotImplementedError('This should be implemented.') | raise NotImplementedError('This should be implemented.') | ||||
def open_file(self, *args): | def open_file(self, *args): | ||||
"""Updating existing file. | """Updating existing file. | ||||
""" | """ | ||||
path = os.fsencode(args[0]) | path = os.fsencode(args[0]) | ||||
self.directory[path] = Content() | self.directory[path] = Content() | ||||
return SWHFileEditor(self.directory, rootpath=self.rootpath, path=path) | return FileEditor(self.directory, rootpath=self.rootpath, path=path) | ||||
def add_file(self, path, copyfrom_path=None, copyfrom_rev=-1): | def add_file(self, path, copyfrom_path=None, copyfrom_rev=-1): | ||||
"""Creating a new file. | """Creating a new file. | ||||
""" | """ | ||||
path = os.fsencode(path) | path = os.fsencode(path) | ||||
self.directory[path] = Content() | self.directory[path] = Content() | ||||
return SWHFileEditor(self.directory, self.rootpath, path) | return FileEditor(self.directory, self.rootpath, path) | ||||
def change_prop(self, key, value): | def change_prop(self, key, value): | ||||
"""Change property callback on directory. | """Change property callback on directory. | ||||
""" | """ | ||||
if key == properties.PROP_EXTERNALS: | if key == properties.PROP_EXTERNALS: | ||||
raise ValueError( | raise ValueError( | ||||
"Property '%s' detected. Not implemented yet." % key) | "Property '%s' detected. Not implemented yet." % key) | ||||
def delete_entry(self, path, revision): | def delete_entry(self, path, revision): | ||||
"""Remove a path. | """Remove a path. | ||||
""" | """ | ||||
self.remove_child(path.encode('utf-8')) | self.remove_child(path.encode('utf-8')) | ||||
def close(self): | def close(self): | ||||
"""Function called when we finish walking a repository. | """Function called when we finish walking a repository. | ||||
""" | """ | ||||
self.update_checksum() | self.update_checksum() | ||||
class SWHDirEditor(BaseDirSWHEditor): | class DirEditor(BaseDirEditor): | ||||
"""Directory Editor in charge of updating directory hashes computation. | """Directory Editor in charge of updating directory hashes computation. | ||||
This implementation includes empty folder in the hash computation. | This implementation includes empty folder in the hash computation. | ||||
""" | """ | ||||
def update_checksum(self): | def update_checksum(self): | ||||
"""Update the root path self.path's checksums according to the | """Update the root path self.path's checksums according to the | ||||
children's objects. | children's objects. | ||||
Show All 15 Lines | def add_directory(self, path, copyfrom_path=None, copyfrom_rev=-1): | ||||
""" | """ | ||||
path = os.fsencode(path) | path = os.fsencode(path) | ||||
os.makedirs(os.path.join(self.rootpath, path), exist_ok=True) | os.makedirs(os.path.join(self.rootpath, path), exist_ok=True) | ||||
self.directory[path] = Directory() | self.directory[path] = Directory() | ||||
return self | return self | ||||
class SWHEditor: | class Editor: | ||||
"""SWH Editor in charge of replaying svn events and computing objects | """Editor in charge of replaying svn events and computing objects | ||||
along. | along. | ||||
This implementation accounts for empty folder during hash | This implementation accounts for empty folder during hash | ||||
computations. | computations. | ||||
""" | """ | ||||
def __init__(self, rootpath, directory): | def __init__(self, rootpath, directory): | ||||
self.rootpath = rootpath | self.rootpath = rootpath | ||||
self.directory = directory | self.directory = directory | ||||
def set_target_revision(self, revnum): | def set_target_revision(self, revnum): | ||||
pass | pass | ||||
def abort(self): | def abort(self): | ||||
pass | pass | ||||
def close(self): | def close(self): | ||||
pass | pass | ||||
def open_root(self, base_revnum): | def open_root(self, base_revnum): | ||||
return SWHDirEditor(self.directory, rootpath=self.rootpath) | return DirEditor(self.directory, rootpath=self.rootpath) | ||||
class SWHReplay: | class Replay: | ||||
"""Replay class. | """Replay class. | ||||
""" | """ | ||||
def __init__(self, conn, rootpath, directory=None): | def __init__(self, conn, rootpath, directory=None): | ||||
self.conn = conn | self.conn = conn | ||||
self.rootpath = rootpath | self.rootpath = rootpath | ||||
if directory is None: | if directory is None: | ||||
directory = Directory() | directory = Directory() | ||||
self.directory = directory | self.directory = directory | ||||
self.editor = SWHEditor(rootpath=rootpath, directory=directory) | self.editor = Editor(rootpath=rootpath, directory=directory) | ||||
def replay(self, rev): | def replay(self, rev): | ||||
"""Replay svn actions between rev and rev+1. | """Replay svn actions between rev and rev+1. | ||||
This method updates in place the self.editor.directory, as well as the | This method updates in place the self.editor.directory, as well as the | ||||
filesystem. | filesystem. | ||||
Returns: | Returns: | ||||
Show All 28 Lines | @click.option('--revision-start', default=1, type=click.INT, | ||||
help="svn repository's starting revision.") | help="svn repository's starting revision.") | ||||
@click.option('--revision-end', default=-1, type=click.INT, | @click.option('--revision-end', default=-1, type=click.INT, | ||||
help="svn repository's ending revision.") | help="svn repository's ending revision.") | ||||
@click.option('--debug/--nodebug', default=True, | @click.option('--debug/--nodebug', default=True, | ||||
help="Indicates if the server should run in debug mode.") | help="Indicates if the server should run in debug mode.") | ||||
@click.option('--cleanup/--nocleanup', default=True, | @click.option('--cleanup/--nocleanup', default=True, | ||||
help="Indicates whether to cleanup disk when done or not.") | help="Indicates whether to cleanup disk when done or not.") | ||||
def main(local_url, svn_url, revision_start, revision_end, debug, cleanup): | def main(local_url, svn_url, revision_start, revision_end, debug, cleanup): | ||||
"""Script to present how to use SWHReplay class. | """Script to present how to use Replay class. | ||||
""" | """ | ||||
conn = RemoteAccess(svn_url.encode('utf-8'), | conn = RemoteAccess(svn_url.encode('utf-8'), | ||||
auth=Auth([get_username_provider()])) | auth=Auth([get_username_provider()])) | ||||
os.makedirs(local_url, exist_ok=True) | os.makedirs(local_url, exist_ok=True) | ||||
rootpath = tempfile.mkdtemp(prefix=local_url, | rootpath = tempfile.mkdtemp(prefix=local_url, | ||||
suffix='-'+os.path.basename(svn_url)) | suffix='-'+os.path.basename(svn_url)) | ||||
rootpath = os.fsencode(rootpath) | rootpath = os.fsencode(rootpath) | ||||
# Do not go beyond the repository's latest revision | # Do not go beyond the repository's latest revision | ||||
revision_end_max = conn.get_latest_revnum() | revision_end_max = conn.get_latest_revnum() | ||||
if revision_end == -1: | if revision_end == -1: | ||||
revision_end = revision_end_max | revision_end = revision_end_max | ||||
revision_end = min(revision_end, revision_end_max) | revision_end = min(revision_end, revision_end_max) | ||||
try: | try: | ||||
replay = SWHReplay(conn, rootpath) | replay = Replay(conn, rootpath) | ||||
for rev in range(revision_start, revision_end+1): | for rev in range(revision_start, revision_end+1): | ||||
objects = replay.compute_hashes(rev) | objects = replay.compute_hashes(rev) | ||||
print("r%s %s (%s new contents, %s new directories)" % ( | print("r%s %s (%s new contents, %s new directories)" % ( | ||||
rev, | rev, | ||||
hashutil.hash_to_hex(replay.directory.hash), | hashutil.hash_to_hex(replay.directory.hash), | ||||
len(objects.get('content', {})), | len(objects.get('content', {})), | ||||
len(objects.get('directory', {})), | len(objects.get('directory', {})), | ||||
Show All 12 Lines |