1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
|
## -*- tcl -*-
# # ## ### ##### ######## ############# #####################
## Copyright (c) 2007 Andreas Kupries.
#
# This software is licensed as described in the file LICENSE, which
# you should have received as part of this distribution.
#
# This software consists of voluntary contributions made by many
# individuals. For exact contribution history, see the revision
# history and logs, available at http://fossil-scm.hwaci.com/fossil
# # ## ### ##### ######## ############# #####################
## Pass III. This pass divides the symbols collected by the previous
## pass into branches, tags, and excludes. The latter are also
## partially deleted by this pass, not only marked. It is the next
## pass however, 'FilterSym', which performs the full deletion.
# # ## ### ##### ######## ############# #####################
## Requirements
package require Tcl 8.4 ; # Required runtime.
package require snit ; # OO system.
package require vc::tools::trouble ; # Error reporting.
package require vc::tools::log ; # User feedback.
package require vc::fossil::import::cvs::repository ; # Repository management.
package require vc::fossil::import::cvs::state ; # State storage.
package require vc::fossil::import::cvs::project::sym ; # Project level symbols
# # ## ### ##### ######## ############# #####################
## Register the pass with the management
vc::fossil::import::cvs::pass define \
CollateSymbols \
{Collate symbols} \
::vc::fossil::import::cvs::pass::collsym
# # ## ### ##### ######## ############# #####################
##
snit::type ::vc::fossil::import::cvs::pass::collsym {
# # ## ### ##### ######## #############
## Public API
typemethod setup {} {
# Define names and structure of the persistent state of this
# pass.
state use project
state use symbol
state use symtype
state use blocker
state use parent
state extend preferedparent {
-- For each symbol the prefered parent. This describes the
-- tree of the found lines of development. Actually a
-- forest in case of multiple projects, with one tree per
-- project.
sid INTEGER NOT NULL PRIMARY KEY REFERENCES symbol,
pid INTEGER NOT NULL REFERENCES symbol
} { pid }
# Index on: pid (branch successors)
return
}
typemethod load {} {
# Pass manager interface. Executed to load data computed by
# this pass into memory when this pass is skipped instead of
# executed.
# The results of this pass are fully in the persistent state,
# there is nothing to load for the next one.
return
}
typemethod run {} {
# Pass manager interface. Executed to perform the
# functionality of the pass.
state transaction {
repository determinesymboltypes
project::sym printrulestatistics
project::sym printtypestatistics
}
if {![trouble ?]} {
UnconvertedSymbols
BadSymbolTypes
BlockedExcludes
InvalidTags
}
if {![trouble ?]} {
DropExcludedSymbolsFromReferences
DeterminePreferedParents
}
log write 1 collsym "Collation completed"
return
}
typemethod discard {} {
# Pass manager interface. Executed for all passes after the
# run passes, to remove all data of this pass from the state,
# as being out of date.
state discard preferedparent
return
}
# # ## ### ##### ######## #############
## Internal methods
## TODO: Move UnconvertedSymbols, BadSymbolTypes, BlockedIncludes,
## TODO: InvalidTags to the integrity module?
proc UnconvertedSymbols {} {
# Paranoia - Have we left symbols without conversion
# information (i.e. with type 'undefined') ?
set undef [project::sym undef]
state foreachrow {
SELECT P.name AS pname, S.name AS sname
FROM symbol S, project P
WHERE S.type = $undef -- Restrict to undefined symbols
AND P.pid = S.pid -- Get project for symbol
} {
trouble fatal "$pname : The symbol '$sname' was left undefined"
}
return
}
proc BadSymbolTypes {} {
# Paranoia - Have we left symbols with bogus conversion
# information (type out of the valid range (excluded, branch,
# tag)) ?
state foreachrow {
SELECT P.name AS pname, S.name AS sname
FROM symbol S, project P
WHERE S.type NOT IN (0,1,2) -- Restrict to symbols with bogus type codes
AND P.pid = S.pid -- Get project of symbol
} {
trouble fatal "$pname : The symbol '$sname' has no proper conversion type"
}
return
}
proc BlockedExcludes {} {
# Paranoia - Have we scheduled symbols for exclusion without
# also excluding their dependent symbols ?
set excl [project::sym excluded]
state foreachrow {
SELECT P.name AS pname, S.name AS sname, SB.name AS bname
FROM symbol S, blocker B, symbol SB, project P
WHERE S.type = $excl -- Restrict to excluded symbols
AND S.sid = B.sid -- Get symbols blocking them
AND B.bid = SB.sid -- and
AND SB.type != $excl -- which are not excluded themselves
AND P.pid = S.pid -- Get project of symbol
} {
trouble fatal "$pname : The symbol '$sname' cannot be excluded as the unexcluded symbol '$bname' depends on it."
}
return
}
proc InvalidTags {} {
# Paranoia - Have we scheduled symbols for conversion as tags
# which absolutely cannot be converted as tags due to commits
# made on them ?
# In other words, this checks finds out if the user has asked
# nonsensical conversions of symbols, which should have been
# left to the heuristics, most specifically
# 'project::sym.HasCommits()'.
set tag [project::sym tag]
state foreachrow {
SELECT P.name AS pname, S.name AS sname
FROM project P, symbol S
WHERE S.type = $tag -- Restrict to tag symbols
AND S.commit_count > 0 -- which have revisions committed to them
AND P.pid = S.pid -- Get project of symbol
} {
trouble fatal "$pname : The symbol '$sname' cannot be forced to be converted as tag because it has commits."
}
return
}
proc DropExcludedSymbolsFromReferences {} {
# The excluded symbols cann be used as blockers nor as
# possible parent for other symbols. We now drop the relevant
# entries to prevent them from causing confusion later on.
set excl [project::sym excluded]
state run {
DELETE FROM blocker
WHERE bid IN (SELECT sid
FROM symbol
WhERE type = $excl); -- Get excluded symbols
DELETE FROM parent
WHERE pid IN (SELECT sid
FROM symbol
WhERE type = $excl); -- Get excluded symbols
}
return
}
proc DeterminePreferedParents {} {
array set prefered {}
set excl [project::sym excluded]
# Phase I: Pull the possible parents, using sorting to put the
# prefered parent of each symbol last among all
# candidates, allowing us get the prefered one by
# each candidate overwriting all previous
# selections. Note that we ignore excluded symbols,
# we do not care about their prefered parents and do
# not attempt to compute them.
state foreachrow {
SELECT S.sid AS xs,
P.pid AS xp,
S.name AS sname,
SB.name AS pname,
PR.name AS prname,
P.n AS votes
FROM symbol S, parent P, symbol SB, project PR
WHERE S.type != $excl -- Restrict to wanted symbols
AND S.sid = P.sid -- Get possible parents of symbol
AND P.pid = SB.sid -- and
AND S.pid = PR.pid -- the project of the symbol
ORDER BY P.n ASC, P.pid DESC -- Sorting, see below
--
-- Higher votes and smaller ids (= earlier branches) last
-- We simply keep the last possible parent for each
-- symbol. This parent will have the max number of votes
-- for its symbol and will be the earliest created branch
-- possible among all with many votes.
} {
log write 9 pcollsym "Voting $votes for Parent($sname) = $pname"
set prefered($xs) [list $xp $sname $pname $prname]
}
# Phase II: Write the found preferences back into the table
# this pass defined for it.
foreach {s x} [array get prefered] {
struct::list assign $x p sname pname prname
state run {
INSERT INTO preferedparent (sid, pid)
VALUES ($s, $p);
}
log write 3 pcollsym "$prname : '$sname's prefered parent is '$pname'"
}
# Phase III: Check the result that all symbols except for
# trunks have a prefered parent. We also ignore
# excluded symbols, as we intentionally did not
# compute a prefered parent for them, see phase I.
state foreachrow {
SELECT PR.name AS pname, S.name AS sname
FROM symbol S LEFT OUTER JOIN preferedparent P
ON S.sid = P.sid, -- From symbol to prefered parent
project PR
WHERE P.pid IS NULL -- restrict to symbols without a preference
AND S.type != $excl -- which are not excluded
AND S.name != ':trunk:' -- and are not a trunk
AND S.pid = PR.pid -- get project of symbol
} {
trouble fatal "$pname : '$sname' has no prefered parent."
}
# The reverse, having prefered parents for unknown symbols
# cannot occur.
return
}
# # ## ### ##### ######## #############
## Configuration
pragma -hasinstances no ; # singleton
pragma -hastypeinfo no ; # no introspection
pragma -hastypedestroy no ; # immortal
# # ## ### ##### ######## #############
}
namespace eval ::vc::fossil::import::cvs::pass {
namespace export collsym
namespace eval collsym {
namespace import ::vc::fossil::import::cvs::repository
namespace import ::vc::fossil::import::cvs::state
namespace eval project {
namespace import ::vc::fossil::import::cvs::project::sym
}
namespace import ::vc::tools::trouble
namespace import ::vc::tools::log
log register collsym
}
}
# # ## ### ##### ######## ############# #####################
## Ready
package provide vc::fossil::import::cvs::pass::collsym 1.0
return
|