source: peerreviewplugin/tags/0.12/3.1/codereview/repo.py

Last change on this file was 17269, checked in by Cinc-th, 5 years ago

PeerReviewPlugin: change exception handling from except <ExceptionName>, e: to except <ExceptionName> as e:

File size: 7.5 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2016 Cinc
4# All rights reserved.
5#
6# This software is licensed as described in the file COPYING.txt, which
7# you should have received as part of this distribution.
8#
9# Author: Cinc
10#
11
12import hashlib
13import os
14from trac.versioncontrol.api import NoSuchNode, RepositoryManager
15from .model import ReviewFileModel
16
17__author__ = 'Cinc'
18__license__ = "BSD"
19
20
21def hash_from_file_node(node):
22    content = node.get_content()
23    blocksize = 4096
24    hasher = hashlib.sha256()
25
26    buf = content.read(blocksize)
27    while len(buf) > 0:
28        hasher.update(buf)
29        buf = content.read(blocksize)
30    return hasher.hexdigest()
31
32
33def repo_path_exists(env, path, reponame=''):
34    repos = RepositoryManager(env).get_repository(reponame)
35    if not repos:
36        return False
37
38    rev = repos.youngest_rev
39    try:
40        node = repos.get_node(path, rev)
41        return node.isdir
42    except NoSuchNode as e:
43        return False
44
45
46def get_node(repos, path, rev):
47    try:
48        return repos.get_node(path, rev)
49    except NoSuchNode as e:
50        return None
51
52from svn_externals import parse_externals
53
54
55def get_nodes_for_dir(env, repodict, dir_node, fnodes, ignore_ext, follow_ext):
56    """Get file nodes recursively for a given directory node.
57
58    :param env: Trac environment object
59    :param repodict: dict holding info about known repositories
60    :param dir_node: a trac directory node
61    :param fnodes: list of file info nodes. Info for found files will be appended.
62    :param ignore_ext: list of file extensions to be ignored
63    :param follow_ext: if True follow externals to folders in the same or another repository
64
65    :return errors: list of errors. Empty list if no errors occurred.
66    """
67    errors = []
68    for node in dir_node.get_entries():
69        if node.isdir:
70            errors += get_nodes_for_dir(env, repodict, node, fnodes, ignore_ext, follow_ext)
71            if follow_ext:
72                props = node.get_properties()
73                try:
74                    for external in parse_externals(props['svn:externals']):
75                        try:
76
77                            # list of lists. First item is len of common prefix, second is repository object
78                            len_common = []
79                            for key, val in repodict.iteritems():
80                                try:
81                                    len_common.append([len(os.path.commonprefix([external['url'], val['url']])),
82                                                       val['repo']])
83                                except KeyError:
84                                    pass
85                            len_common.sort(reverse=True)
86                            # First item in list is repo holding the external path because it has the longest
87                            # common prefix
88                            repos = len_common[0][1]
89                            repo_path = repodict[repos.reponame]['prefix'] + '/' + \
90                                external['url'][len_common[0][0]:].lstrip('/')
91                            ext_node = get_node(repos, repo_path, external['rev'])
92                            if ext_node:
93                                errors += get_nodes_for_dir(env, repodict, ext_node, fnodes, ignore_ext, follow_ext)
94                            else:
95                                txt = "No node for external path '%s' in repository '%s'. " \
96                                      "External: '%s %s' was ignored for directory '%s'." \
97                                      % (repo_path, repos.reponame, external['url'], external['dir'], node.name)
98                                env.log.warning(txt)
99                                errors.append(txt)
100                        except KeyError:  # Missing data in dictionary e.g. we try to use aan unnamed repository
101                            txt = "External: '%s %s' was ignored for directory '%s'." %\
102                                  (external['url'], external['dir'], node.name)
103                            env.log.warning(txt)
104                            errors.append(txt)
105                except KeyError:  # property has no svn:externals
106                    pass
107        else:
108            if os.path.splitext(node.path)[1].lower() not in ignore_ext:
109                fnodes.append({
110                    'path': node.path,
111                    'rev': node.rev,
112                    'change_rev':node.created_rev,
113                    'hash': hash_from_file_node(node)
114                })
115    return errors
116
117
118def file_data_from_repo(node, keyword_substitution=False):
119
120    dat = u''
121    if keyword_substitution:
122        content = node.get_processed_content()
123    else:
124        content = node.get_content()
125    res = content.read()
126    while res:
127        dat += res.decode('utf-8')  # We assume 'utf-8' here. In fact it may be anything.
128        res = content.read()
129    return dat.splitlines()
130
131
132def get_repository_dict(env):
133    """Get a dict with information about all repositories.
134
135    :param env: Trac environment object
136    :return: dict with key = reponame, value = dict with information about repository.
137
138    The information about a repository is queried using ''get_all_repositories'' from
139    RepositoryManager.
140    - For any real repository (that means not an alias) the Repository object
141      is inserted into the dictionary using the key 'repo'.
142    - For any real repository (that means not an alias) a prefix is calculated from the url info
143      and inserted using the key 'prefix'. This prefix is used to build paths into the repository.
144
145    """
146    repoman = RepositoryManager(env)
147
148    repolist = repoman.get_all_repositories()  # repolist is a dict with key = reponame, val = dict
149    for repo in repoman.get_real_repositories():
150        repolist[repo.reponame]['repo'] = repoman.get_repository(repo.reponame)
151        # We need the last part of the path later when following externals
152        try:
153            repolist[repo.reponame]['prefix'] = '/' + os.path.basename(repolist[repo.reponame]['url'].rstrip('/'))
154        except KeyError:
155            repolist[repo.reponame]['prefix'] = ''
156    return repolist
157
158
159def insert_project_files(self, src_path, project, ignore_ext, follow_ext=False, rev=None, reponame=''):
160    """Add project files to the database.
161
162    :param self: Trac component object
163    :param src_path
164    """
165    repolist = get_repository_dict(self.env)
166    try:
167        repos = repolist[reponame]['repo']
168    except KeyError:
169        return
170
171    if not repos:
172        return
173
174    if rev:
175        rev = repos.normalize_rev(rev)
176    rev_or_latest = rev or repos.youngest_rev
177
178    root_node = get_node(repos, src_path, rev_or_latest)
179
180    fnodes = []
181    if root_node.isdir:
182        errors = get_nodes_for_dir(self.env, repolist, root_node, fnodes, ignore_ext, follow_ext)
183    else:
184        errors = []
185
186    ReviewFileModel.delete_files_by_project_name(self.env, project)
187    @self.env.with_transaction()
188    def insert_data(db):
189        cursor = db.cursor()
190        for item in fnodes:
191            cursor.execute("INSERT INTO peerreviewfile"
192                           "(review_id,path,line_start,line_end,repo,revision, changerevision,hash,project)"
193                           "VALUES (0, %s, 0, 0, %s, %s, %s, %s, %s)",
194                           (item['path'], reponame, item['rev'], item['change_rev'], item['hash'], project))
195
196    return errors, len(fnodes)
Note: See TracBrowser for help on using the repository browser.