SHA1 Hash: | 38b967dcf5613a918fcddcde269df452ce378752 |
---|---|
Date: | 2007-11-17 00:29:42 |
User: | drh |
Comment: | Merge aku's CVS import changes into the main line. Fix a small bug in diff.c. |
Timelines: | ancestors | descendants | both | trunk |
Other Links: | files | ZIP archive | manifest |
- branch=trunk inherited from [a28c83647d]
- sym-trunk inherited from [a28c83647d]
Added art/CollRev1.dia version [186c7bb7a8]
@@ -1,1 +1,793 @@ - +<?xml version="1.0" encoding="UTF-8"?> +<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/"> + <dia:diagramdata> + <dia:attribute name="background"> + <dia:color val="#ffffff"/> + </dia:attribute> + <dia:attribute name="pagebreak"> + <dia:color val="#000099"/> + </dia:attribute> + <dia:attribute name="paper"> + <dia:composite type="paper"> + <dia:attribute name="name"> + <dia:string>#Letter#</dia:string> + </dia:attribute> + <dia:attribute name="tmargin"> + <dia:real val="2.5399999618530273"/> + </dia:attribute> + <dia:attribute name="bmargin"> + <dia:real val="2.5399999618530273"/> + </dia:attribute> + <dia:attribute name="lmargin"> + <dia:real val="2.5399999618530273"/> + </dia:attribute> + <dia:attribute name="rmargin"> + <dia:real val="2.5399999618530273"/> + </dia:attribute> + <dia:attribute name="is_portrait"> + <dia:boolean val="true"/> + </dia:attribute> + <dia:attribute name="scaling"> + <dia:real val="1"/> + </dia:attribute> + <dia:attribute name="fitto"> + <dia:boolean val="false"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="grid"> + <dia:composite type="grid"> + <dia:attribute name="width_x"> + <dia:real val="1"/> + </dia:attribute> + <dia:attribute name="width_y"> + <dia:real val="1"/> + </dia:attribute> + <dia:attribute name="visible_x"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="visible_y"> + <dia:int val="1"/> + </dia:attribute> + <dia:composite type="color"/> + </dia:composite> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#d8e5e5"/> + </dia:attribute> + <dia:attribute name="guides"> + <dia:composite type="guides"> + <dia:attribute name="hguides"/> + <dia:attribute name="vguides"/> + </dia:composite> + </dia:attribute> + </dia:diagramdata> + <dia:layer name="Background" visible="true"> + <dia:group> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O0"> + <dia:attribute name="obj_pos"> + <dia:point val="15,13"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="14.95,12.95;20.05,15.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="15,13"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="5"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O1"> + <dia:attribute name="obj_pos"> + <dia:point val="16.2733,14.064"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="16.2733,13.5215;18.7096,14.4615"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#Revision#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="16.2733,14.064"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O2"> + <dia:attribute name="obj_pos"> + <dia:point val="15,7"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="14.95,6.95;20.05,9.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="15,7"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="5"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O3"> + <dia:attribute name="obj_pos"> + <dia:point val="17.0039,8.06397"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="17.0039,7.52147;17.979,8.46147"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#File#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="17.0039,8.06397"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O4"> + <dia:attribute name="obj_pos"> + <dia:point val="15,1"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="14.95,0.95;20.05,3.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="15,1"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="5"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O5"> + <dia:attribute name="obj_pos"> + <dia:point val="16.4942,2.06397"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="16.4942,1.52147;18.4887,2.46147"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#Project#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="16.4942,2.06397"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:object type="Standard - ZigZagLine" version="1" id="O6"> + <dia:attribute name="obj_pos"> + <dia:point val="17.5,13"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="17.45,8.92929;17.55,13"/> + </dia:attribute> + <dia:attribute name="orth_points"> + <dia:point val="17.5,13"/> + <dia:point val="17.5,13"/> + <dia:point val="17.5,9"/> + <dia:point val="17.5,9"/> + </dia:attribute> + <dia:attribute name="orth_orient"> + <dia:enum val="0"/> + <dia:enum val="1"/> + <dia:enum val="0"/> + </dia:attribute> + <dia:attribute name="autorouting"> + <dia:boolean val="true"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - ZigZagLine" version="1" id="O7"> + <dia:attribute name="obj_pos"> + <dia:point val="17.5,7"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="17.45,2.92929;17.55,7"/> + </dia:attribute> + <dia:attribute name="orth_points"> + <dia:point val="17.5,7"/> + <dia:point val="17.5,7"/> + <dia:point val="17.5,3"/> + <dia:point val="17.5,3"/> + </dia:attribute> + <dia:attribute name="orth_orient"> + <dia:enum val="0"/> + <dia:enum val="1"/> + <dia:enum val="0"/> + </dia:attribute> + <dia:attribute name="autorouting"> + <dia:boolean val="true"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O8"> + <dia:attribute name="obj_pos"> + <dia:point val="15,19"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="14.95,18.95;20.05,21.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="15,19"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="5"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O9"> + <dia:attribute name="obj_pos"> + <dia:point val="16.7775,20.064"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="16.7775,19.5215;18.2225,20.4615"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#Meta#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="16.7775,20.064"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:object type="Standard - PolyLine" version="0" id="O10"> + <dia:attribute name="obj_pos"> + <dia:point val="15,20"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="7.5,14.95;15.05,20.05"/> + </dia:attribute> + <dia:attribute name="poly_points"> + <dia:point val="15,20"/> + <dia:point val="8,20"/> + <dia:point val="8,15"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O11"> + <dia:attribute name="obj_pos"> + <dia:point val="15,14"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="10.95,13.5;15.05,14.5"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="15,14"/> + <dia:point val="11,14"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - ZigZagLine" version="1" id="O12"> + <dia:attribute name="obj_pos"> + <dia:point val="20,20"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="19.95,1.5;27.05,20.05"/> + </dia:attribute> + <dia:attribute name="orth_points"> + <dia:point val="20,20"/> + <dia:point val="27,20"/> + <dia:point val="27,2"/> + <dia:point val="20,2"/> + </dia:attribute> + <dia:attribute name="orth_orient"> + <dia:enum val="0"/> + <dia:enum val="1"/> + <dia:enum val="0"/> + </dia:attribute> + <dia:attribute name="autorouting"> + <dia:boolean val="false"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O13"> + <dia:attribute name="obj_pos"> + <dia:point val="17.5,15"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="17,14.95;18,19.05"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="17.5,15"/> + <dia:point val="17.5,19"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - PolyLine" version="0" id="O14"> + <dia:attribute name="obj_pos"> + <dia:point val="8,13"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="7.95,1.5;15.05,13.05"/> + </dia:attribute> + <dia:attribute name="poly_points"> + <dia:point val="8,13"/> + <dia:point val="8,2"/> + <dia:point val="15,2"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O15"> + <dia:attribute name="obj_pos"> + <dia:point val="5,13"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="4.95,12.95;11.05,15.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="5,13"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="6"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O16"> + <dia:attribute name="obj_pos"> + <dia:point val="6.91375,14.0725"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="6.91375,13.53;9.08625,14.47"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#Symbol#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="6.91375,14.0725"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:object type="Standard - Text" version="1" id="O17"> + <dia:attribute name="obj_pos"> + <dia:point val="18,12"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="18,11.4575;21.06,12.3975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#belongs to#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="18,12"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O18"> + <dia:attribute name="obj_pos"> + <dia:point val="18,6"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="18,5.4575;21.06,6.3975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#belongs to#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="18,6"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O19"> + <dia:attribute name="obj_pos"> + <dia:point val="18,16"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="18,15.4575;19.03,16.3975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#has#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="18,16"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O20"> + <dia:attribute name="obj_pos"> + <dia:point val="21,20"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="21,19.4575;24.06,20.3975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#belongs to#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="21,20"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O21"> + <dia:attribute name="obj_pos"> + <dia:point val="11,20"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="11,19.4575;14.06,20.3975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#belongs to#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="11,20"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O22"> + <dia:attribute name="obj_pos"> + <dia:point val="12,15"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="12,14.4575;15.06,15.3975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#belongs to#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="12,15"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O23"> + <dia:attribute name="obj_pos"> + <dia:point val="9,12"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="9,11.4575;12.06,12.3975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#belongs to#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="9,12"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O24"> + <dia:attribute name="obj_pos"> + <dia:point val="1,13"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="1,12.4575;10.5175,13.3975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#(Line of Development / Branch)#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="1,13"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + </dia:layer> +</dia:diagram>
Added art/CollRev2.dia version [59b1c331a5]
@@ -1,1 +1,576 @@ - +<?xml version="1.0" encoding="UTF-8"?> +<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/"> + <dia:diagramdata> + <dia:attribute name="background"> + <dia:color val="#ffffff"/> + </dia:attribute> + <dia:attribute name="pagebreak"> + <dia:color val="#000099"/> + </dia:attribute> + <dia:attribute name="paper"> + <dia:composite type="paper"> + <dia:attribute name="name"> + <dia:string>#Letter#</dia:string> + </dia:attribute> + <dia:attribute name="tmargin"> + <dia:real val="2.5399999618530273"/> + </dia:attribute> + <dia:attribute name="bmargin"> + <dia:real val="2.5399999618530273"/> + </dia:attribute> + <dia:attribute name="lmargin"> + <dia:real val="2.5399999618530273"/> + </dia:attribute> + <dia:attribute name="rmargin"> + <dia:real val="2.5399999618530273"/> + </dia:attribute> + <dia:attribute name="is_portrait"> + <dia:boolean val="true"/> + </dia:attribute> + <dia:attribute name="scaling"> + <dia:real val="1"/> + </dia:attribute> + <dia:attribute name="fitto"> + <dia:boolean val="false"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="grid"> + <dia:composite type="grid"> + <dia:attribute name="width_x"> + <dia:real val="1"/> + </dia:attribute> + <dia:attribute name="width_y"> + <dia:real val="1"/> + </dia:attribute> + <dia:attribute name="visible_x"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="visible_y"> + <dia:int val="1"/> + </dia:attribute> + <dia:composite type="color"/> + </dia:composite> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#d8e5e5"/> + </dia:attribute> + <dia:attribute name="guides"> + <dia:composite type="guides"> + <dia:attribute name="hguides"/> + <dia:attribute name="vguides"/> + </dia:composite> + </dia:attribute> + </dia:diagramdata> + <dia:layer name="Background" visible="true"> + <dia:group> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O0"> + <dia:attribute name="obj_pos"> + <dia:point val="13,1"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="12.95,0.95;20.05,3.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="13,1"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="7"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O1"> + <dia:attribute name="obj_pos"> + <dia:point val="15.2818,2.06397"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="15.2818,1.52147;17.7182,2.46147"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#Revision#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="15.2818,2.06397"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O2"> + <dia:attribute name="obj_pos"> + <dia:point val="13,7"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="12.95,6.95;20.05,9.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="13,7"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="7"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O3"> + <dia:attribute name="obj_pos"> + <dia:point val="14.1456,8.06397"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="14.1456,7.52147;18.8544,8.46147"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#Revision' (Child)#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="14.1456,8.06397"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O4"> + <dia:attribute name="obj_pos"> + <dia:point val="2,2"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="1.95,1.95;9.05,4.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="2,2"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="7"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O5"> + <dia:attribute name="obj_pos"> + <dia:point val="5.00393,3.06397"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="5.00393,2.52147;5.97901,3.46147"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#File#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="5.00393,3.06397"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:object type="Standard - Line" version="0" id="O6"> + <dia:attribute name="obj_pos"> + <dia:point val="13,8"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="8.83023,6.5028;13.0606,8.06063"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="13,8"/> + <dia:point val="9,7"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O7"> + <dia:attribute name="obj_pos"> + <dia:point val="13,2"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="8.83023,1.93937;13.0606,3.4972"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="13,2"/> + <dia:point val="9,3"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O8"> + <dia:attribute name="obj_pos"> + <dia:point val="13,2"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="8.57833,1.92972;13.0703,7.35139"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="13,2"/> + <dia:point val="9,7"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O9"> + <dia:attribute name="obj_pos"> + <dia:point val="13,8"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="8.57833,2.64861;13.0703,8.07028"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="13,8"/> + <dia:point val="9,3"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O10"> + <dia:attribute name="obj_pos"> + <dia:point val="2,6"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="1.95,5.95;9.05,8.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="2,6"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="7"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O11"> + <dia:attribute name="obj_pos"> + <dia:point val="3.53147,6.6725"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="3.53147,6.13;7.45147,7.87"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#Line of +Development#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="3.53147,6.6725"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:object type="Standard - Text" version="1" id="O12"> + <dia:attribute name="obj_pos"> + <dia:point val="18,6"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="18,5.4575;20.0947,6.3975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string># parent#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="18,6"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O13"> + <dia:attribute name="obj_pos"> + <dia:point val="18,7"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="17.5,2.95;18.5,7.05"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="18,7"/> + <dia:point val="18,3"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:group> + <dia:object type="Standard - Text" version="1" id="O14"> + <dia:attribute name="obj_pos"> + <dia:point val="22,7"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="22,6.4575;28.4122,8.1975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#branch parent symbol + (NULL)#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="22,7"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O15"> + <dia:attribute name="obj_pos"> + <dia:point val="20,8"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="19.95,7.5;22.05,8.5"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="20,8"/> + <dia:point val="22,8"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Polygon" version="0" id="O16"> + <dia:attribute name="obj_pos"> + <dia:point val="23,7"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="21.9293,6.87929;23.05,9.12071"/> + </dia:attribute> + <dia:attribute name="poly_points"> + <dia:point val="23,7"/> + <dia:point val="22,8"/> + <dia:point val="23,9"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:object type="Standard - Text" version="1" id="O17"> + <dia:attribute name="obj_pos"> + <dia:point val="15,4"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="15,3.4575;16.57,4.3975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string># child#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="15,4"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O18"> + <dia:attribute name="obj_pos"> + <dia:point val="15,3"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="14.5,2.95;15.5,7.05"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="15,3"/> + <dia:point val="15,7"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + </dia:group> + </dia:layer> +</dia:diagram>
Added art/CollRev3.dia version [d14a7b35e0]
@@ -1,1 +1,980 @@ - +<?xml version="1.0" encoding="UTF-8"?> +<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/"> + <dia:diagramdata> + <dia:attribute name="background"> + <dia:color val="#ffffff"/> + </dia:attribute> + <dia:attribute name="pagebreak"> + <dia:color val="#000099"/> + </dia:attribute> + <dia:attribute name="paper"> + <dia:composite type="paper"> + <dia:attribute name="name"> + <dia:string>#Letter#</dia:string> + </dia:attribute> + <dia:attribute name="tmargin"> + <dia:real val="2.5399999618530273"/> + </dia:attribute> + <dia:attribute name="bmargin"> + <dia:real val="2.5399999618530273"/> + </dia:attribute> + <dia:attribute name="lmargin"> + <dia:real val="2.5399999618530273"/> + </dia:attribute> + <dia:attribute name="rmargin"> + <dia:real val="2.5399999618530273"/> + </dia:attribute> + <dia:attribute name="is_portrait"> + <dia:boolean val="true"/> + </dia:attribute> + <dia:attribute name="scaling"> + <dia:real val="1"/> + </dia:attribute> + <dia:attribute name="fitto"> + <dia:boolean val="false"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="grid"> + <dia:composite type="grid"> + <dia:attribute name="width_x"> + <dia:real val="1"/> + </dia:attribute> + <dia:attribute name="width_y"> + <dia:real val="1"/> + </dia:attribute> + <dia:attribute name="visible_x"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="visible_y"> + <dia:int val="1"/> + </dia:attribute> + <dia:composite type="color"/> + </dia:composite> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#d8e5e5"/> + </dia:attribute> + <dia:attribute name="guides"> + <dia:composite type="guides"> + <dia:attribute name="hguides"/> + <dia:attribute name="vguides"/> + </dia:composite> + </dia:attribute> + </dia:diagramdata> + <dia:layer name="Background" visible="true"> + <dia:group> + <dia:object type="Standard - Text" version="1" id="O0"> + <dia:attribute name="obj_pos"> + <dia:point val="7,15"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="7,14.6;7,15.8"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>##</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="7,15"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O1"> + <dia:attribute name="obj_pos"> + <dia:point val="13,1"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="12.95,0.95;19.05,3.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="13,1"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="6"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O2"> + <dia:attribute name="obj_pos"> + <dia:point val="14.04,1.66397"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="14.04,1.12147;17.96,2.86147"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#Line of +Development#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="14.04,1.66397"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O3"> + <dia:attribute name="obj_pos"> + <dia:point val="3,1"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="2.95,0.95;9.05,3.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="3,1"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="6"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O4"> + <dia:attribute name="obj_pos"> + <dia:point val="4.04,1.66397"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="4.04,1.12147;7.96,2.86147"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#Line' of +Development#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="4.04,1.66397"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O5"> + <dia:attribute name="obj_pos"> + <dia:point val="3,13"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="2.95,12.95;9.05,15.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="3,13"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="6"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O6"> + <dia:attribute name="obj_pos"> + <dia:point val="3.94,13.664"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="3.94,13.1215;8.06,14.8615"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#Revision'' +(Branch Start)#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="3.94,13.664"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O7"> + <dia:attribute name="obj_pos"> + <dia:point val="13,7"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="12.95,6.95;19.05,9.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="13,7"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="6"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O8"> + <dia:attribute name="obj_pos"> + <dia:point val="14.7733,8.0725"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="14.7733,7.53;17.2096,8.47"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#Revision#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="14.7733,8.0725"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O9"> + <dia:attribute name="obj_pos"> + <dia:point val="23,13"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="22.95,12.95;29.05,15.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="23,13"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="6"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O10"> + <dia:attribute name="obj_pos"> + <dia:point val="25.5039,14.0725"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="25.5039,13.53;26.479,14.47"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#File#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="25.5039,14.0725"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O11"> + <dia:attribute name="obj_pos"> + <dia:point val="13,13"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="12.95,12.95;19.05,15.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="13,13"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="6"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O12"> + <dia:attribute name="obj_pos"> + <dia:point val="14.6933,13.6725"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="14.6933,13.13;17.2896,14.87"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#Revision' +(Child)#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="14.6933,13.6725"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:object type="Standard - Line" version="0" id="O13"> + <dia:attribute name="obj_pos"> + <dia:point val="19,14"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="18.95,13.5;23.05,14.5"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="19,14"/> + <dia:point val="23,14"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O14"> + <dia:attribute name="obj_pos"> + <dia:point val="6,13"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="5.5,2.95;6.5,13.05"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="6,13"/> + <dia:point val="6,3"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O15"> + <dia:attribute name="obj_pos"> + <dia:point val="18,9"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="17.5,8.95;18.5,13.05"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="18,9"/> + <dia:point val="18,13"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O16"> + <dia:attribute name="obj_pos"> + <dia:point val="16,7"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="15.5,2.95;16.5,7.05"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="16,7"/> + <dia:point val="16,3"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O17"> + <dia:attribute name="obj_pos"> + <dia:point val="14,13"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="13.5,8.95;14.5,13.05"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="14,13"/> + <dia:point val="14,9"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - ZigZagLine" version="1" id="O18"> + <dia:attribute name="obj_pos"> + <dia:point val="9,14"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="8.95,7.5;13.05,14.05"/> + </dia:attribute> + <dia:attribute name="orth_points"> + <dia:point val="9,14"/> + <dia:point val="11,14"/> + <dia:point val="11,8"/> + <dia:point val="13,8"/> + </dia:attribute> + <dia:attribute name="orth_orient"> + <dia:enum val="0"/> + <dia:enum val="1"/> + <dia:enum val="0"/> + </dia:attribute> + <dia:attribute name="autorouting"> + <dia:boolean val="true"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - ZigZagLine" version="1" id="O19"> + <dia:attribute name="obj_pos"> + <dia:point val="6,15"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="5.95,14.95;26.5,17.05"/> + </dia:attribute> + <dia:attribute name="orth_points"> + <dia:point val="6,15"/> + <dia:point val="6,17"/> + <dia:point val="26,17"/> + <dia:point val="26,15"/> + </dia:attribute> + <dia:attribute name="orth_orient"> + <dia:enum val="1"/> + <dia:enum val="0"/> + <dia:enum val="1"/> + </dia:attribute> + <dia:attribute name="autorouting"> + <dia:boolean val="false"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - ZigZagLine" version="1" id="O20"> + <dia:attribute name="obj_pos"> + <dia:point val="19,8"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="18.95,7.95;26.5,13.05"/> + </dia:attribute> + <dia:attribute name="orth_points"> + <dia:point val="19,8"/> + <dia:point val="26,8"/> + <dia:point val="26,13"/> + </dia:attribute> + <dia:attribute name="orth_orient"> + <dia:enum val="0"/> + <dia:enum val="1"/> + </dia:attribute> + <dia:attribute name="autorouting"> + <dia:boolean val="true"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O21"> + <dia:attribute name="obj_pos"> + <dia:point val="6,12"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="6,11.4575;8.2125,13.1975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string># branch + parent#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="6,12"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O22"> + <dia:attribute name="obj_pos"> + <dia:point val="14,12"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="14,11.4575;16.0947,12.3975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string># parent#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="14,12"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O23"> + <dia:attribute name="obj_pos"> + <dia:point val="18,10"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="18,9.4575;19.57,10.3975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string># child#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="18,10"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O24"> + <dia:attribute name="obj_pos"> + <dia:point val="19,7"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="19,6.52875;22.245,8.39875"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string># + belongs to#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="19,7"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O25"> + <dia:attribute name="obj_pos"> + <dia:point val="6,15"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="6,14.4575;9.245,16.1975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string># + belongs to#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="6,15"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O26"> + <dia:attribute name="obj_pos"> + <dia:point val="19,13"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="19,12.5288;22.245,14.3987"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string># + belongs to#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="19,13"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O27"> + <dia:attribute name="obj_pos"> + <dia:point val="9,14"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="9,13.5288;11.0947,15.3987"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string># + parent#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="9,14"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - ZigZagLine" version="1" id="O28"> + <dia:attribute name="obj_pos"> + <dia:point val="3,14"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="0.95,1.5;3.05,14.05"/> + </dia:attribute> + <dia:attribute name="orth_points"> + <dia:point val="3,14"/> + <dia:point val="1,14"/> + <dia:point val="1,2"/> + <dia:point val="3,2"/> + </dia:attribute> + <dia:attribute name="orth_orient"> + <dia:enum val="0"/> + <dia:enum val="1"/> + <dia:enum val="0"/> + </dia:attribute> + <dia:attribute name="autorouting"> + <dia:boolean val="false"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O29"> + <dia:attribute name="obj_pos"> + <dia:point val="1,12"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="1,11.4575;4.245,12.3975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string># belongs to#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="1,12"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O30"> + <dia:attribute name="obj_pos"> + <dia:point val="10,2.12153"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="10,1.10403;12.205,2.86403"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#=/=#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="1.5"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="10,2.12153"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + </dia:layer> +</dia:diagram>
Added art/CollRev4.dia version [be6e84c213]
@@ -1,1 +1,640 @@ - +<?xml version="1.0" encoding="UTF-8"?> +<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/"> + <dia:diagramdata> + <dia:attribute name="background"> + <dia:color val="#ffffff"/> + </dia:attribute> + <dia:attribute name="pagebreak"> + <dia:color val="#000099"/> + </dia:attribute> + <dia:attribute name="paper"> + <dia:composite type="paper"> + <dia:attribute name="name"> + <dia:string>#Letter#</dia:string> + </dia:attribute> + <dia:attribute name="tmargin"> + <dia:real val="2.5399999618530273"/> + </dia:attribute> + <dia:attribute name="bmargin"> + <dia:real val="2.5399999618530273"/> + </dia:attribute> + <dia:attribute name="lmargin"> + <dia:real val="2.5399999618530273"/> + </dia:attribute> + <dia:attribute name="rmargin"> + <dia:real val="2.5399999618530273"/> + </dia:attribute> + <dia:attribute name="is_portrait"> + <dia:boolean val="true"/> + </dia:attribute> + <dia:attribute name="scaling"> + <dia:real val="1"/> + </dia:attribute> + <dia:attribute name="fitto"> + <dia:boolean val="false"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="grid"> + <dia:composite type="grid"> + <dia:attribute name="width_x"> + <dia:real val="1"/> + </dia:attribute> + <dia:attribute name="width_y"> + <dia:real val="1"/> + </dia:attribute> + <dia:attribute name="visible_x"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="visible_y"> + <dia:int val="1"/> + </dia:attribute> + <dia:composite type="color"/> + </dia:composite> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#d8e5e5"/> + </dia:attribute> + <dia:attribute name="guides"> + <dia:composite type="guides"> + <dia:attribute name="hguides"/> + <dia:attribute name="vguides"/> + </dia:composite> + </dia:attribute> + </dia:diagramdata> + <dia:layer name="Background" visible="true"> + <dia:group> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O0"> + <dia:attribute name="obj_pos"> + <dia:point val="3,8"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="2.95,7.95;9.05,10.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="3,8"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="6"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O1"> + <dia:attribute name="obj_pos"> + <dia:point val="4.11647,8.66397"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="4.11647,8.12147;7.86647,9.86147"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#Revision' +(Child NTDB)#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="4.11647,8.66397"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O2"> + <dia:attribute name="obj_pos"> + <dia:point val="5,1"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="4.95,0.95;11.05,3.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="5,1"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="6"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O3"> + <dia:attribute name="obj_pos"> + <dia:point val="6.78184,1.6725"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="6.78184,1.13;9.21816,2.87"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#Revision +(NTDB)#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="6.78184,1.6725"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O4"> + <dia:attribute name="obj_pos"> + <dia:point val="1,15"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="0.95,14.95;7.05,17.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="1,15"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="6"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O5"> + <dia:attribute name="obj_pos"> + <dia:point val="2.11647,15.664"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="2.11647,15.1215;5.86647,16.8615"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#Revision'' +(Child NTDB)#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="2.11647,15.664"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:group> + <dia:object type="Standard - Box" version="0" id="O6"> + <dia:attribute name="obj_pos"> + <dia:point val="13,13"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="12.95,12.95;19.05,15.05"/> + </dia:attribute> + <dia:attribute name="elem_corner"> + <dia:point val="13,13"/> + </dia:attribute> + <dia:attribute name="elem_width"> + <dia:real val="6"/> + </dia:attribute> + <dia:attribute name="elem_height"> + <dia:real val="2"/> + </dia:attribute> + <dia:attribute name="show_background"> + <dia:boolean val="true"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O7"> + <dia:attribute name="obj_pos"> + <dia:point val="14.2915,13.664"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="14.2915,13.1215;17.6915,14.8615"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string>#Revision"" +(non-NTDB)#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="14.2915,13.664"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + <dia:object type="Standard - Line" version="0" id="O8"> + <dia:attribute name="obj_pos"> + <dia:point val="8,8"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="7.93501,2.76788;10.4828,8.06499"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="8,8"/> + <dia:point val="10,3"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O9"> + <dia:attribute name="obj_pos"> + <dia:point val="6,3"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="3.51719,2.93501;6.06499,8.23212"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="6,3"/> + <dia:point val="4,8"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O10"> + <dia:attribute name="obj_pos"> + <dia:point val="4,10"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="1.51719,9.93501;4.06499,15.2321"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="4,10"/> + <dia:point val="2,15"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O11"> + <dia:attribute name="obj_pos"> + <dia:point val="6,15"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="5.93501,9.76788;8.48281,15.065"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="6,15"/> + <dia:point val="8,10"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O12"> + <dia:attribute name="obj_pos"> + <dia:point val="16,13"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="8.70852,8.54107;16.0682,13.0682"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="16,13"/> + <dia:point val="9,9"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Line" version="0" id="O13"> + <dia:attribute name="obj_pos"> + <dia:point val="6,10"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="5.93178,9.93178;13.2915,14.4589"/> + </dia:attribute> + <dia:attribute name="conn_endpoints"> + <dia:point val="6,10"/> + <dia:point val="13,14"/> + </dia:attribute> + <dia:attribute name="numcp"> + <dia:int val="1"/> + </dia:attribute> + <dia:attribute name="end_arrow"> + <dia:enum val="22"/> + </dia:attribute> + <dia:attribute name="end_arrow_length"> + <dia:real val="0.5"/> + </dia:attribute> + <dia:attribute name="end_arrow_width"> + <dia:real val="0.5"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O14"> + <dia:attribute name="obj_pos"> + <dia:point val="6,14"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="6,13.5288;8.27969,15.3987"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string># + parent#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="6,14"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O15"> + <dia:attribute name="obj_pos"> + <dia:point val="6,3"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="6,2.4575;7.385,4.1975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string># +child#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="6,3"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O16"> + <dia:attribute name="obj_pos"> + <dia:point val="4,10"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="4,9.4575;5.385,11.1975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string># +child#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="4,10"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O17"> + <dia:attribute name="obj_pos"> + <dia:point val="15,12"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="15,11.5288;18.3897,13.3987"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string># + dbparent#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="15,12"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O18"> + <dia:attribute name="obj_pos"> + <dia:point val="9,12"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="9,11.4575;11.865,12.3975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string># dbchild#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="9,12"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + <dia:object type="Standard - Text" version="1" id="O19"> + <dia:attribute name="obj_pos"> + <dia:point val="8,7"/> + </dia:attribute> + <dia:attribute name="obj_bb"> + <dia:rectangle val="8,6.4575;10.2797,8.1975"/> + </dia:attribute> + <dia:attribute name="text"> + <dia:composite type="text"> + <dia:attribute name="string"> + <dia:string># + parent#</dia:string> + </dia:attribute> + <dia:attribute name="font"> + <dia:font family="sans" style="0" name="Helvetica"/> + </dia:attribute> + <dia:attribute name="height"> + <dia:real val="0.80000000000000004"/> + </dia:attribute> + <dia:attribute name="pos"> + <dia:point val="8,7"/> + </dia:attribute> + <dia:attribute name="color"> + <dia:color val="#000000"/> + </dia:attribute> + <dia:attribute name="alignment"> + <dia:enum val="0"/> + </dia:attribute> + </dia:composite> + </dia:attribute> + <dia:attribute name="valign"> + <dia:enum val="3"/> + </dia:attribute> + </dia:object> + </dia:group> + </dia:layer> +</dia:diagram>
Modified src/diff.c from [017b424914] to [fe83b4caec].
@@ -23,11 +23,11 @@ ** ** This file contains code used to compute a "diff" between two ** text files. */ #include "config.h" -#include "diff2.h" +#include "diff.h" #include <assert.h> #if 0 #define DEBUG(X) X
Added tools/cvs2fossil/cvs2fossil version [df73a69477]
@@ -1,1 +1,32 @@ +#!/bin/sh +## -*- tcl -*- \ +exec tclsh "$0" ${1+"$@"} + +# # ## ### ##### ######## ############# ##################### +## 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 +# # ## ### ##### ######## ############# ##################### + +## Command line application wrapped around the import packages. + +# # ## ### ##### ######## ############# ##################### +## Requirements, extended package management for local packages. + +lappend auto_path [file join [file dirname [info script]] lib] + +package require Tcl 8.4 ; # Required runtime. +package require vc::fossil::import::cvs ; # Main functionality. + +# # ## ### ##### ######## ############# ##################### +## Execution + +vc::fossil::import::cvs run $argv +exit 0 +# # ## ### ##### ######## ############# #####################
Added tools/cvs2fossil/doc/LICENSE version [aede671429]
@@ -1,1 +1,19 @@ +This code is under the same license as fossil itself. + +- - -- --- ----- --------- + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public +License version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +- - -- --- ----- ---------
Added tools/cvs2fossil/doc/README version [6d655c3f82]
@@ -1,1 +1,7 @@ +[Acknowledge the work done by the creators of and submitters to the +cvs2svn project/application. Needed their documentation, notes, and +code as guide for this implementation.] + +[Determine if their license allows me to copy their notes here for +reference.]
Added tools/cvs2fossil/lib/c2f_cyclebreaker.tcl version [41093323e5]
@@ -1,1 +1,291 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## This file provides a helper package for the passes 6 and 7 which +## contains the common code of the cycle breaking algorithm. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require struct::graph ; # Graph handling. +package require struct::list ; # Higher order list operations. +package require vc::tools::log ; # User feedback. +package require vc::tools::misc ; # Text formatting. +package require vc::fossil::import::cvs::project::rev ; # Project level changesets +package require vc::fossil::import::cvs::project::revlink ; # Cycle links. + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::cyclebreaker { + # # ## ### ##### ######## ############# + ## Public API + + typemethod run {changesets {savecmd {}}} { + ::variable save $savecmd + ::variable at 0 + + # We create a graph of the revision changesets, using the file + # level dependencies to construct a first approximation of the + # dependencies at the project level. Then we look for cycles + # in that graph and break them. + + # 1. Create nodes for all relevant changesets and a mapping + # from the revisions to their changesets/nodes. + + log write 3 cyclebreaker "Creating changeset graph, filling with nodes" + log write 3 cyclebreaker "Adding [nsp [llength $changesets] node]" + + set dg [struct::graph dg] + + foreach cset $changesets { + dg node insert $cset + dg node set $cset timerange [$cset timerange] + } + + # 2. Find for all relevant changeset their revisions and their + # dependencies. Map the latter back to changesets and + # construct the corresponding arcs. + + log write 3 cyclebreaker {Setting up node dependencies} + + foreach cset $changesets { + foreach succ [$cset successors] { + # Changesets may have dependencies outside of the + # chosen set. These are ignored + if {![dg node exists $succ]} continue + dg arc insert $cset $succ + } + } + + # 3. Lastly we iterate the graph topologically. We mark off + # the nodes which have no predecessors, in order from + # oldest to youngest, saving and removing dependencies. If + # we find no nodes without predecessors we have a cycle, + # and work on breaking it. + + log write 3 cyclebreaker {Now sorting the changesets, breaking cycles} + + InitializeCandidates $dg + while {1} { + while {[WithoutPredecessor $dg n]} { + SaveAndRemove $dg $n + } + if {![llength [dg nodes]]} break + BreakCycle $dg [FindCycle $dg] + InitializeCandidates $dg + } + + dg destroy + + log write 3 cyclebreaker Done. + return + } + + # # ## ### ##### ######## ############# + ## Internal methods + + # Instead of searching the whole graph for the degree-0 nodes in + # each iteration we compute the list once to start, and then only + # update it incrementally based on the outgoing neighbours of the + # node chosen for commit. + + proc InitializeCandidates {dg} { + # bottom = list (list (node, range min, range max)) + ::variable bottom + foreach n [$dg nodes] { + if {[$dg node degree -in $n]} continue + lappend bottom [linsert [$dg node get $n timerange] 0 $n] + } + set bottom [lsort -index 1 -integer [lsort -index 2 -integer $bottom]] + return + } + + proc WithoutPredecessor {dg nv} { + ::variable bottom + + upvar 1 $nv n + if {![llength $bottom]} { return 0 } + + set n [lindex [lindex $bottom 0] 0] + set bottom [lrange $bottom 1 end] + set changed 0 + + # Update list of nodes without predecessor, based on the + # outgoing neighbours of the chosen node. This should be + # faster than iterating of the whole set of nodes, finding all + # without predecessors, sorting them by time, etc. pp. + foreach out [$dg nodes -out $n] { + if {[$dg node degree -in $out] > 1} continue + # Degree-1 neighbour, will have no predecessors after the + # removal of n. Put on the list. + lappend bottom [linsert [$dg node get $out timerange] 0 $out] + set changed 1 + } + if {$changed} { + set bottom [lsort -index 1 -integer [lsort -index 2 -integer $bottom]] + } + + # We do not delete the node immediately, to allow the Save + # procedure to save the dependencies as well (encoded in the + # arcs). + return 1 + } + + proc SaveAndRemove {dg n} { + ::variable at + ::variable save + + # Give the user of the cycle breaker the opportunity to work + # with the changeset before it is removed from the graph. + + if {[llength $save]} { + uplevel #0 [linsert $save end $at $n] + } + + incr at + $dg node delete $n + return + } + + proc FindCycle {dg} { + # This procedure is run if and only the graph is not empty and + # all nodes have predecessors. This means that each node is + # either part of a cycle or (indirectly) depending on a node + # in a cycle. We can start at an arbitrary node, follow its + # incoming edges to its predecessors until we see a node a + # second time. That node closes the cycle and the beginning is + # its first occurence. Note that we can choose an arbitrary + # predecessor of each node as well, we do not have to search. + + # We record for each node the index of the first appearance in + # the path, making it easy at the end to cut the cycle from + # it. + + # Choose arbitrary node to start our search at. + set start [lindex [$dg nodes] 0] + + # Initialize state, path of seen nodes, and when seen. + set path {} + array set seen {} + + while {1} { + # Stop searching when we have seen the current node + # already, the circle has been closed. + if {[info exists seen($start)]} break + lappend path $start + set seen($start) [expr {[llength $path]-1}] + # Choose arbitrary predecessor + set start [lindex [$dg nodes -in $start] 0] + } + + return [struct::list reverse [lrange $path $seen($start) end]] + } + + proc ID {cset} { return "<[$cset id]>" } + + proc BreakCycle {dg cycle} { + # The cycle we have gotten is broken by breaking apart one or + # more of the changesets in the cycle. This causes us to + # create one or more changesets which are to be committed, + # added to the graph, etc. pp. + + set cprint [join [struct::list map $cycle [myproc ID]] { }] + + lappend cycle [lindex $cycle 0] [lindex $cycle 1] + set bestlink {} + set bestnode {} + + foreach \ + prev [lrange $cycle 0 end-2] \ + cset [lrange $cycle 1 end-1] \ + next [lrange $cycle 2 end] { + + # Each triple PREV -> CSET -> NEXT of changesets, a + # 'link' in the cycle, is analysed and the best + # location where to at least weaken the cycle is + # chosen for further processing. + + set link [project::revlink %AUTO% $prev $cset $next] + if {$bestlink eq ""} { + set bestlink $link + set bestnode $cset + } elseif {[$link betterthan $bestlink]} { + $bestlink destroy + set bestlink $link + set bestnode $cset + } else { + $link destroy + } + } + + log write 5 breakrcycle "Breaking cycle ($cprint) by splitting changeset <[$bestnode id]>" + + set newcsets [$bestlink break] + $bestlink destroy + + # At this point the old changeset (BESTNODE) is gone + # already. We remove it from the graph as well and then enter + # the fragments generated for it. + + $dg node delete $bestnode + + foreach cset $newcsets { + $dg node insert $cset + $dg node set $cset timerange [$cset timerange] + } + + foreach cset $newcsets { + foreach succ [$cset successors] { + # The new changesets may have dependencies outside of + # the chosen set. These are ignored + if {![$dg node exists $succ]} continue + $dg arc insert $cset $succ + } + } + return + } + + typevariable at 0 ; # Counter for commit ids for the changesets. + typevariable bottom {} ; # List of candidate nodes for committing. + typevariable save {} ; # The command to call for each processed node + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs { + namespace export cyclebreaker + namespace eval cyclebreaker { + namespace eval project { + namespace import ::vc::fossil::import::cvs::project::rev + namespace import ::vc::fossil::import::cvs::project::revlink + } + namespace import ::vc::tools::misc::* + namespace import ::vc::tools::log + log register cyclebreaker + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::cyclebreaker 1.0 +return
Added tools/cvs2fossil/lib/c2f_file.tcl version [a0a48d681e]
@@ -1,1 +1,1113 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## File, part of a project, part of a CVS repository. Multiple +## instances are possible. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require struct::set ; # Set operations. +package require vc::fossil::import::cvs::file::rev ; # CVS per file revisions. +package require vc::fossil::import::cvs::file::sym ; # CVS per file symbols. +package require vc::fossil::import::cvs::state ; # State storage. +package require vc::tools::trouble ; # Error reporting. +package require vc::tools::log ; # User feedback +package require vc::tools::misc ; # Text formatting + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::file { + # # ## ### ##### ######## ############# + ## Public API + + constructor {id path usrpath executable project} { + set myid $id + set mypath $path + set myusrpath $usrpath + set myexecutable $executable + set myproject $project + set mytrunk [$myproject trunk] + return + } + + method setid {id} { + if {$myid ne ""} { trouble internal "File '$mypath' already has an id, '$myid'" } + set myid $id + return + } + + method id {} { return $myid } + method path {} { return $mypath } + method usrpath {} { return $myusrpath } + method project {} { return $myproject } + + delegate method commitmessageof to myproject + + # # ## ### ##### ######## ############# + ## Methods required for the class to be a sink of the rcs parser + + #method begin {} {puts begin} + #method sethead {h} {puts head=$h} + #method setprincipalbranch {b} {puts pb=$b} + #method deftag {s r} {puts $s=$r} + #method setcomment {c} {puts comment=$c} + #method admindone {} {puts admindone} + #method def {rev date author state next branches} {puts "def $rev $date $author $state $next $branches"} + #method defdone {} {puts def-done} + #method setdesc {d} {puts desc=$d} + #method extend {rev commitmsg deltarange} {puts "extend $commitmsg $deltarange"} + #method done {} {puts done} + + # # ## ### ##### ######## ############# + ## Persistence (pass II) + + method persist {} { + # First collect the reachable revisions and symbols, then + # assign id's to all. They are sorted so that we will have ids + # which sort in order of creation. Then we can save them. This + # is done bottom up. Revisions, then symbols. __NOTE__ This + # works only because sqlite is not checking foreign key + # references during insert. This allows to have dangling + # references which are fixed later. The longest dangling + # references are for the project level symbols, these we do + # not save here, but at the end of the pass. What we need are + # the ids, hence the two phases. + + struct::list assign [$self Active] revisions symbols + foreach rev $revisions { $rev defid } + foreach sym $symbols { $sym defid } + + state transaction { + foreach rev $revisions { $rev persist } + foreach sym $symbols { $sym persist } + } + return + } + + method drop {} { + foreach {_ rev} [array get myrev] { $rev destroy } + foreach {_ branch} [array get mybranches] { $branch destroy } + foreach {_ taglist} [array get mytags] { + foreach tag $taglist { $tag destroy } + } + return + } + + # # ## ### ##### ######## ############# + ## Implement the sink + + method begin {} {#ignore} + + method sethead {revnr} { + set myheadrevnr $revnr + return + } + + method setprincipalbranch {branchnr} { + set myprincipal $branchnr + return + } + + method deftag {name revnr} { + # FUTURE: Perform symbol transformation here. + + if {[struct::set contains $mysymbols $name]} { + trouble fatal "Multiple definitions of the symbol '$name' in '$mypath'" + return + } + + struct::set add mysymbols $name + + if {[rev isbranchrevnr $revnr -> branchnr]} { + $self AddBranch $name $branchnr + } else { + $self AddTag $name $revnr + } + return + } + + method setcomment {c} {# ignore} + + method admindone {} { + # We do nothing at the boundary of admin and revision data + } + + method def {revnr date author state next branches} { + $self RecordBranchCommits $branches + + if {[info exists myrev($revnr)]} { + trouble fatal "File $mypath contains duplicate definitions for revision $revnr." + return + } + + set myaid($revnr) [$myproject defauthor $author] + set myrev($revnr) [rev %AUTO% $revnr $date $state $self] + + $self RecordBasicDependencies $revnr $next + return + } + + method defdone {} { + # This is all done after the revision tree has been extracted + # from the file, before the commit mesages and delta texts are + # processed. + + $self ProcessPrimaryDependencies + $self ProcessBranchDependencies + $self SortBranches + $self ProcessTagDependencies + $self DetermineTheRootRevision + return + } + + method setdesc {d} {# ignore} + + method extend {revnr commitmsg textrange} { + set cmid [$myproject defcmessage [string trim $commitmsg]] + + set rev $myrev($revnr) + + if {[$rev hasmeta]} { + # Apparently repositories exist in which the delta data + # for revision 1.1 is provided several times, at least + # twice. The actual cause of this duplication is not + # known. Speculation centers on RCS/CVS bugs, or from + # manual edits of the repository which borked the + # internals. Whatever the cause, testing showed that both + # cvs and rcs use the first definition when performing a + # checkout, and we follow their lead. Side notes: 'cvs + # log' fails on such a file, and 'cvs rlog' prints the log + # message from the first delta, ignoring the second. + + log write 1 file "In file $mypath : Duplicate delta data for revision $revnr" + log write 1 file "Ignoring the duplicate" + return + } + + # Determine the line of development for the revision (project + # level). This gives us the branchid too, required for the + # meta data group the revision is in. (Note: By putting both + # branch/lod and project information into the group we ensure + # that any cross-project and cross-branch commits are + # separated into multiple commits, one in each of the projects + # and/or branches). + + set lod [$self GetLOD $revnr] + + $rev setmeta [$myproject defmeta [$lod id] $myaid($revnr) $cmid] + $rev settext $textrange + $rev setlod $lod + + # If this is revision 1.1, we have to determine whether the + # file seems to have been created through 'cvs add' instead of + # 'cvs import'. This can be done by looking at the un- + # adulterated commit message, as CVS uses a hardwired magic + # message for the latter, i.e. "Initial revision\n", no + # period. (This fact also helps us when the time comes to + # determine whether this file might have had a default branch + # in the past.) + + if {$revnr eq "1.1"} { + set myimported [expr {$commitmsg eq "Initial revision\n"}] + } + + # Here we also keep track of the order in which the revisions + # were added to the file. + + lappend myrevisions $rev + return + } + + method done {} { + # Complete the revisions, branches, and tags. This includes + # looking for a non-trunk default branch, marking its members + # and linking them into the trunk, possibly excluding + # non-trunk data, and collecting aggregate symbol statistics. + + $self DetermineRevisionOperations + $self DetermineLinesOfDevelopment + $self HandleNonTrunkDefaultBranch + $self RemoveIrrelevantDeletions + $self RemoveInitialBranchDeletions + + if {[$myproject trunkonly]} { + $self ExcludeNonTrunkInformation + } + + $self AggregateSymbolData + return + } + + # # ## ### ##### ######## ############# + ## State + + variable myid {} ; # File id in the persistent state. + variable mypath {} ; # Path of the file's rcs archive. + variable myusrpath {} ; # Path of the file as seen by users. + variable myexecutable 0 ; # Boolean flag 'file executable'. + variable myproject {} ; # Reference to the project object + # the file belongs to. + variable myrev -array {} ; # Maps revision number to the + # associated revision object. + variable myrevisions {} ; # Same as myrev, but a list, + # giving us the order of + # revisions. + variable myaid -array {} ; # Map revision numbers to the id + # of the author who committed + # it. This is later aggregated + # with commit message, branch name + # and project id for a meta id. + variable myheadrevnr {} ; # Head revision (revision number) + variable myprincipal {} ; # Principal branch (branch number). + # Contrary to the name this is the + # default branch. + variable mydependencies {} ; # Dictionary parent -> child, + # records primary dependencies. + variable myimported 0 ; # Boolean flag. Set if and only if + # rev 1.1 of the file seemingly + # was imported instead of added + # normally. + variable myroot {} ; # Reference to the revision object + # holding the root revision. Its + # number usually is '1.1'. Can be + # a different number, because of + # gaps created via 'cvsadmin -o'. + variable mybranches -array {} ; # Maps branch number to the symbol + # object handling the branch. + variable mytags -array {} ; # Maps revision number to the list + # of symbol objects for the tags + # associated with the revision. + variable mysymbols {} ; # Set of the symbol names found in + # this file. + + variable mybranchcnt 0 ; # Counter for branches, to record their + # order of definition. This also defines + # their order of creation, which is the + # reverse of definition. I.e. a smaller + # number means 'Defined earlier', means + # 'Created later'. + + variable mytrunk {} ; # Direct reference to myproject -> trunk. + variable myroots {} ; # List of roots in the forest of + # lod's. Object references to revisions and + # branches. The latter can appear when they + # are severed from their parent. + + # # ## ### ##### ######## ############# + ## Internal methods + + method RecordBranchCommits {branches} { + foreach branchrevnr $branches { + if {[catch { + set branch [$self Rev2Branch $branchrevnr] + }]} { + set branch [$self AddUnlabeledBranch [rev 2branchnr $branchrevnr]] + } + + # Record the commit, just as revision number for + # now. ProcesBranchDependencies will extend that ito a + # proper object reference. + + $branch setchildrevnr $branchrevnr + } + return + } + + method Rev2Branch {revnr} { + if {[rev istrunkrevnr $revnr]} { + trouble internal "Expected a branch revision number" + } + return $mybranches([rev 2branchnr $revnr]) + } + + method AddUnlabeledBranch {branchnr} { + return [$self AddBranch unlabeled-$branchnr $branchnr] + } + + method AddBranch {name branchnr} { + if {[info exists mybranches($branchnr)]} { + log write 1 file "In '$mypath': Branch '$branchnr' named '[$mybranches($branchnr) name]'" + log write 1 file "Cannot have second name '$name', ignoring it" + return + } + set branch [sym %AUTO% branch $branchnr [$myproject getsymbol $name] $self] + $branch setposition [incr mybranchcnt] + set mybranches($branchnr) $branch + return $branch + } + + method AddTag {name revnr} { + set tag [sym %AUTO% tag $revnr [$myproject getsymbol $name] $self] + lappend mytags($revnr) $tag + return $tag + } + + method RecordBasicDependencies {revnr next} { + # Handle the revision dependencies. Record them for now, do + # nothing with them yet. + + # On the trunk the 'next' field points to the previous + # revision, i.e. the _parent_ of the current one. Example: + # 1.6's next is 1.5 (modulo cvs admin -o). + + # Contrarily on a branch the 'next' field points to the + # primary _child_ of the current revision. As example, + # 1.1.3.2's 'next' will be 1.1.3.3. + + # The 'next' field actually always refers to the revision + # containing the delta needed to retrieve that revision. + + # The dependencies needed here are the logical structure, + # parent/child, and not the implementation dependent delta + # pointers. + + if {$next eq ""} return + # parent -> child + if {[rev istrunkrevnr $revnr]} { + lappend mydependencies $next $revnr + } else { + lappend mydependencies $revnr $next + } + return + } + + method ProcessPrimaryDependencies {} { + foreach {parentrevnr childrevnr} $mydependencies { + set parent $myrev($parentrevnr) + set child $myrev($childrevnr) + $parent setchild $child + $child setparent $parent + } + return + } + + method ProcessBranchDependencies {} { + foreach {branchnr branch} [array get mybranches] { + set revnr [$branch parentrevnr] + + if {![info exists myrev($revnr)]} { + log write 1 file "In '$mypath': The branch '[$branch name]' references" + log write 1 file "the bogus revision '$revnr' and will be ignored." + $branch destroy + unset mybranches($branchnr) + } else { + set rev $myrev($revnr) + $rev addbranch $branch + $branch setparent $rev + + # If revisions were committed on the branch we store a + # reference to the branch there, and further declare + # the first child's parent to be branch's parent, and + # list this child in the parent revision. + + if {[$branch haschildrev]} { + set childrevnr [$branch childrevnr] + set child $myrev($childrevnr) + $branch setchild $child + + $child setparentbranch $branch + $child setparent $rev + $rev addchildonbranch $child + } + } + } + return + } + + method SortBranches {} { + foreach {revnr rev} [array get myrev] { $rev sortbranches } + return + } + + method ProcessTagDependencies {} { + foreach {revnr taglist} [array get mytags] { + if {![info exists myrev($revnr)]} { + set n [llength $taglist] + log write 1 file "In '$mypath': The following [nsp $n tag] reference" + log write 1 file "the bogus revision '$revnr' and will be ignored." + foreach tag $taglist { + log write 1 file " [$tag name]" + $tag destroy + } + unset mytags($revnr) + } else { + set rev $myrev($revnr) + foreach tag $taglist { + $rev addtag $tag + $tag settagrev $rev + } + } + } + return + } + + method DetermineTheRootRevision {} { + # The root is the one revision which has no parent. By + # checking all revisions we ensure that we can detect and + # report the case of multiple roots. Without that we could + # simply take one revision and follow the parent links to + # their root (sic!). + + foreach {revnr rev} [array get myrev] { + if {[$rev hasparent]} continue + if {$myroot ne ""} { trouble internal "Multiple root revisions found" } + set myroot $rev + } + + # In the future we also need a list, as branches can become + # severed from their parent, making them their own root. + set myroots [list $myroot] + return + } + + method DetermineRevisionOperations {} { + foreach rev $myrevisions { $rev determineoperation } + return + } + + method DetermineLinesOfDevelopment {} { + # For revisions this has been done already, in 'extend'. Now + # we do this for the branches and tags. + + foreach {_ branch} [array get mybranches] { + $branch setlod [$self GetLOD [$branch parentrevnr]] + } + + foreach {_ taglist} [array get mytags] { + foreach tag $taglist { + $tag setlod [$self GetLOD [$tag tagrevnr]] + } + } + return + } + + method GetLOD {revnr} { + if {[rev istrunkrevnr $revnr]} { + return $mytrunk + } else { + return [$self Rev2Branch $revnr] + } + } + + method HandleNonTrunkDefaultBranch {} { + set revlist [$self NonTrunkDefaultRevisions] + if {![llength $revlist]} return + + $self AdjustNonTrunkDefaultBranch $revlist + $self CheckLODs + return + } + + method NonTrunkDefaultRevisions {} { + # From cvs2svn the following explanation (with modifications + # for our algorithm): + + # Determine whether there are any non-trunk default branch + # revisions. + + # If a non-trunk default branch is determined to have existed, + # return a list of objects for all revisions that were once + # non-trunk default revisions, in dependency order (i.e. root + # first). + + # There are two cases to handle: + + # One case is simple. The RCS file lists a default branch + # explicitly in its header, such as '1.1.1'. In this case, we + # know that every revision on the vendor branch is to be + # treated as head of trunk at that point in time. + + # But there's also a degenerate case. The RCS file does not + # currently have a default branch, yet we can deduce that for + # some period in the past it probably *did* have one. For + # example, the file has vendor revisions 1.1.1.1 -> 1.1.1.96, + # all of which are dated before 1.2, and then it has 1.1.1.97 + # -> 1.1.1.100 dated after 1.2. In this case, we should + # record 1.1.1.96 as the last vendor revision to have been the + # head of the default branch. + + if {$myprincipal ne ""} { + # There is still a default branch; that means that all + # revisions on that branch get marked. + + log write 5 file "Found explicitly marked NTDB" + + set rnext [$myroot child] + if {$rnext ne ""} { + trouble fatal "File with default branch $myprincipal also has revision [$rnext revnr]" + return + } + + set rev [$mybranches($myprincipal) child] + set res {} + + while {$rev ne ""} { + lappend res $rev + set rev [$rev child] + } + + return $res + + } elseif {$myimported} { + # No default branch, but the file appears to have been + # imported. So our educated guess is that all revisions + # on the '1.1.1' branch with timestamps prior to the + # timestamp of '1.2' were non-trunk default branch + # revisions. + + # This really only processes standard '1.1.1.*'-style + # vendor revisions. One could conceivably have a file + # whose default branch is 1.1.3 or whatever, or was that + # at some point in time, with vendor revisions 1.1.3.1, + # 1.1.3.2, etc. But with the default branch gone now, + # we'd have no basis for assuming that the non-standard + # vendor branch had ever been the default branch anyway. + + # Note that we rely on comparisons between the timestamps + # of the revisions on the vendor branch and that of + # revision 1.2, even though the timestamps might be + # incorrect due to clock skew. We could do a slightly + # better job if we used the changeset timestamps, as it is + # possible that the dependencies that went into + # determining those timestamps are more accurate. But + # that would require an extra pass or two. + + if {![info exists mybranches(1.1.1)]} { return {} } + + log write 5 file "Deduced existence of NTDB" + + set rev [$mybranches(1.1.1) child] + set res {} + set stop [$myroot child] + + if {$stop eq ""} { + # Get everything on the branch + while {$rev ne ""} { + lappend res $rev + set rev [$rev child] + } + } else { + # Collect everything on the branch which seems to have + # been committed before the first primary child of the + # root revision. + set stopdate [$stop date] + while {$rev ne ""} { + if {[$rev date] >= $stopdate} break + lappend res $rev + set rev [$rev child] + } + } + + return $res + + } else { + return {} + } + } + + # General note: In the following methods we only modify the links + # between revisions and symbols to restructure the revision + # tree. We do __not__ destroy the objects. Given the complex links + # GC is difficult at this level. It is much easier to drop + # everything when we we are done. This happens in 'drop', using + # the state variable 'myrev', 'mybranches', and 'mytags'. What we + # have to persist, performed by 'persist', we know will be + # reachable through the revisions listed in 'myroots' and their + # children and symbols. + + method AdjustNonTrunkDefaultBranch {revlist} { + set stop [$myroot child] ;# rev '1.2' + + log write 5 file "Adjusting NTDB containing [nsp [llength $revlist] revision]" + + # From cvs2svn the following explanation (with modifications + # for our algorithm): + + # Adjust the non-trunk default branch revisions found in the + # 'revlist'. + + # 'myimported' is a boolean flag indicating whether this file + # appears to have been imported, which also means that + # revision 1.1 has a generated log message that need not be + # preserved. 'revlist' is a list of object references for the + # revisions that have been determined to be non-trunk default + # branch revisions. + + # Note that the first revision on the default branch is + # handled strangely by CVS. If a file is imported (as opposed + # to being added), CVS creates a 1.1 revision, then creates a + # vendor branch 1.1.1 based on 1.1, then creates a 1.1.1.1 + # revision that is identical to the 1.1 revision (i.e., its + # deltatext is empty). The log message that the user typed + # when importing is stored with the 1.1.1.1 revision. The 1.1 + # revision always contains a standard, generated log message, + # 'Initial revision\n'. + + # When we detect a straightforward import like this, we want + # to handle it by deleting the 1.1 revision (which doesn't + # contain any useful information) and making 1.1.1.1 into an + # independent root in the file's dependency tree. In SVN, + # 1.1.1.1 will be added directly to the vendor branch with its + # initial content. Then in a special 'post-commit', the + # 1.1.1.1 revision is copied back to trunk. + + # If the user imports again to the same vendor branch, then CVS + # creates revisions 1.1.1.2, 1.1.1.3, etc. on the vendor branch, + # *without* counterparts in trunk (even though these revisions + # effectively play the role of trunk revisions). So after we add + # such revisions to the vendor branch, we also copy them back to + # trunk in post-commits. + + # We mark the revisions found in 'revlist' as default branch + # revisions. Also, if the root revision has a primary child + # we set that revision to depend on the last non-trunk default + # branch revision and possibly adjust its type accordingly. + + set first [lindex $revlist 0] + + log write 6 file "<[$first revnr]> [expr {$myimported ? "imported" : "not imported"}], [$first operation], [expr {[$first hastext] ? "has text" : "no text"}]" + + if {$myimported && + [$first revnr] eq "1.1.1.1" && + [$first operation] eq "change" && + ![$first hastext]} { + + set rev11 [$first parent] ; # Assert: Should be myroot. + log write 3 file "Removing irrelevant revision [$rev11 revnr]" + + # Cut out the old myroot revision. + + ldelete myroots $rev11 ; # Not a root any longer. + + $first cutfromparent ; # Sever revision from parent revision. + if {$stop ne ""} { + $stop cutfromparent + lappend myroots $stop ; # New root, after vendor branch + } + + # Cut out the vendor branch symbol + + set vendor [$first parentbranch] + if {$vendor eq ""} { trouble internal "First NTDB revision has no branch" } + if {[$vendor parent] eq $rev11} { + $rev11 removebranch $vendor + $rev11 removechildonbranch $first + $vendor cutchild + $first cutfromparentbranch + lappend myroots $first + } + + # Change the type of first (typically from Change to Add): + $first retype add + + # Move any tags and branches from the old to the new root. + $rev11 movesymbolsto $first + } + + # Mark all the special revisions as such + foreach rev $revlist { + log write 3 file "Revision on default branch: [$rev revnr]" + $rev setondefaultbranch 1 + } + + if {$stop ne ""} { + # Revision 1.2 logically follows the imported revisions, + # not 1.1. Accordingly, connect it to the last NTDBR and + # possibly change its type. + + set last [lindex $revlist end] + $stop setdefaultbranchparent $last ; # Retypes the revision too. + $last setdefaultbranchchild $stop + } + return + } + + method CheckLODs {} { + foreach {_ branch} [array get mybranches] { $branch checklod } + foreach {_ taglist} [array get mytags] { + foreach tag $taglist { $tag checklod } + } + return + } + + method RemoveIrrelevantDeletions {} { + # From cvs2svn: If a file is added on a branch, then a trunk + # revision is added at the same time in the 'Dead' state. + # This revision doesn't do anything useful, so delete it. + + foreach root $myroots { + if {[$root isneeded]} continue + log write 2 file "Removing unnecessary dead revision [$root revnr]" + + # Remove as root, make its child new root after + # disconnecting it from the revision just going away. + + ldelete myroots $root + if {[$root haschild]} { + set child [$root child] + $child cutfromparent + lappend myroots $child + } + + # Cut out the branches spawned by the revision to be + # deleted. If the branch has revisions they should already + # use operation 'add', no need to change that. The first + # revision on each branch becomes a new and disconnected + # root. + + foreach branch [$root branches] { + if {![$branch haschild]} continue + set first [$branch child] + $first cutfromparentbranch + $first cutfromparent + $branch cutchild + lappend myroots $first + } + $root removeallbranches + + # Tagging a dead revision doesn't do anything, so remove + # any tags that were set on it. + + $root removealltags + + # This can only happen once per file, and we might have + # just changed myroots, so end the loop + break + } + return + } + + method RemoveInitialBranchDeletions {} { + # From cvs2svn: If the first revision on a branch is an + # unnecessary delete, remove it. + # + # If a file is added on a branch (whether or not it already + # existed on trunk), then new versions of CVS add a first + # branch revision in the 'dead' state (to indicate that the + # file did not exist on the branch when the branch was + # created) followed by the second branch revision, which is an + # add. When we encounter this situation, we sever the branch + # from trunk and delete the first branch revision. + + # At this point we may have already multiple roots in myroots, + # we have to process them all. + + foreach root [$self LinesOfDevelopment] { + if {[$root isneededbranchdel]} continue + log write 2 file "Removing unnecessary initial branch delete [$root revnr]" + + set branch [$root parentbranch] + set parent [$root parent] + set child [$root child] + + ldelete myroots $root + lappend myroots $child + + $branch cutchild + $child cutfromparent + + $parent removebranch $branch + $parent removechildonbranch $root + } + return + } + + method LinesOfDevelopment {} { + # Determine all lines of development for the file. This are + # the known roots, and the root of all branches found on the + # line of primary children. + + set lodroots {} + foreach root $myroots { + $self AddBranchedLinesOfDevelopment lodroots $root + lappend lodroots $root + } + return $lodroots + } + + method AddBranchedLinesOfDevelopment {lv root} { + upvar 1 $lv lodroots + while {$root ne ""} { + foreach branch [$root branches] { + if {![$branch haschild]} continue + set child [$branch child] + # Recurse into the branch for deeper branches. + $self AddBranchedLinesOfDevelopment lodroots $child + lappend lodroots $child + } + set root [$root child] + } + return + } + + method ExcludeNonTrunkInformation {} { + # Remove all non-trunk branches, revisions, and tags. We do + # keep the tags which are on the trunk. + + set ntdbroot "" + foreach root [$self LinesOfDevelopment] { + # Note: Here the order of the roots is important, + # i.e. that we get them in depth first order. This ensures + # that the removal of a branch happens only after the + # branches spawned from it were removed. Otherwise the + # system might try to access deleted objects. + + # Do not exclude the trunk. + if {[[$root lod] istrunk]} continue + $self ExcludeBranch $root ntdbroot + } + + if {$ntdbroot ne ""} { + $self GraftNTDB2Trunk $ntdbroot + } + return + } + + method ExcludeBranch {root nv} { + # Exclude the branch/lod starting at root, a revision. + # + # If the LOD starts with non-trunk default branch revisions, + # we leave them in place and do not delete the branch. In that + # case the command sets the variable in NV so that we can + # later rework these revisons to be purely trunk. + + if {[$root isondefaultbranch]} { + # Handling a NTDB. This branch may consists not only of + # NTDB revisions, but also some non-NTDB. The latter are + # truly on a branch and have to be excluded. The following + # loop determines if there are such revisions. + + upvar 1 $nv ntdbroot + set ntdbroot $root + $root cutfromparentbranch + + set rev $root + while {$rev ne ""} { + $rev removeallbranches + # See note [x]. + + if {[$rev isondefaultbranch]} { + set rev [$rev child] + } else { + break + } + } + + # rev now contains the first non-NTDB revision after the + # NTDB, or is empty if there is no such. If we have some + # they have to removed. + + if {$rev ne ""} { + set lastntdb [$rev parent] + $lastntdb cutfromchild + while {$rev ne ""} { + $rev removealltags + $rev removeallbranches + # Note [x]: We may still have had branches on the + # revision. Branches without revisions committed + # on them do not show up in the list of roots aka + # lines of development. + set rev [$rev child] + } + } + return + } + + # No NTDB stuff to deal with. First delete the branch object + # itself, after cutting all the various connections. + + set branch [$root parentbranch] + if {$branch ne ""} { + set branchparent [$branch parent] + $branchparent removebranch $branch + $branchparent removechildonbranch $root + } + + # The root is no such any longer either. + ldelete myroots $root + + # Now go through the line and remove all its revisions. + + while {$root ne ""} { + $root removealltags + $root removeallbranches + # Note: See the note [x]. + + # From cvs2svn: If this is the last default revision on a + # non-trunk default branch followed by a 1.2 revision, + # then the 1.2 revision depends on this one. FIXME: It is + # questionable whether this handling is correct, since the + # non-trunk default branch revisions affect trunk and + # should therefore not just be discarded even if + # --trunk-only. + + if {[$root hasdefaultbranchchild]} { + set ntdbchild [$root defaultbranchchild] + if {[$ntdbchild defaultbranchparent] ne $ntdbchild} { + trouble internal "ntdb - trunk linkage broken" + } + $ntdbchild cutdefaultbranchparent + if {[$ntdbchild hasparent]} { + lappend myroots [$ntdbchild parent] + } + } + + set root [$root child] + } + + return + } + + method GraftNTDB2Trunk {root} { + # We can now graft the non-trunk default branch revisions to + # trunk. They should already be alone on a CVSBranch-less + # branch. + + if {[$root hasparentbranch]} { trouble internal "NTDB root still has its branch symbol" } + if {[$root hasbranches]} { trouble internal "NTDB root still has spawned branches" } + + set last $root + while {[$last haschild]} {set last [$last child]} + + if {[$last hasdefaultbranchchild]} { + + set rev12 [$last defaultbranchchild] + $rev12 cutdefaultbranchparent + $last cutdefaultbranchchild + + $rev12 changeparent $last + $last changechild $rev12 + + ldelete myroots $rev12 + + # Note and remember that the type of rev12 was already + # adjusted by AdjustNonTrunkDefaultBranch, so we don't + # have to change its type here. + } + + while {$root ne ""} { + $root setondefaultbranch 0 + $root setlod $mytrunk + foreach tag [$root tags] { + $tag setlod $mytrunk + } + set root [$root child] + } + + return + } + + method Active {} { + set revisions {} + set symbols {} + + foreach root [$self LinesOfDevelopment] { + if {[$root hasparentbranch]} { lappend symbols [$root parentbranch] } + while {$root ne ""} { + lappend revisions $root + foreach tag [$root tags] { lappend symbols $tag } + foreach branch [$root branches] { lappend symbols $branch } + set lod [$root lod] + if {![$lod istrunk]} { lappend symbols $lod } + set root [$root child] + } + } + + return [list [lsort -unique -dict $revisions] [lsort -unique -dict $symbols]] + } + + + method AggregateSymbolData {} { + # Now that the exact set of revisions (and through that + # branches and tags) is known we can update the aggregate + # symbol statistics. + + foreach root [$self LinesOfDevelopment] { + set lod [$root lod] + + # Note: If the LOD is the trunk the count*, etc. methods + # will do nothing, as it is always present (cannot be + # excluded), and is always a branch too. + + # Lines of development count as branches and have a commit + # on them (root). If they are still attached to a tree we + # have to compute and register possible parents. + + $lod countasbranch + $lod countacommit + + if {[$root hasparentbranch]} { + # Note lod == [$root parentbranch] + $lod possibleparents + } + + # For the revisions in the line we register their branches + # and tags as blockers for the lod, and update the type + # counters as well. As branch symbols without commits on + # them are not listed as lines of development, we have to + # count them here as well, as plain branches. At last we + # have to compute and register the possible parents of the + # tags, in case they are later converted as branches. + + while {$root ne ""} { + foreach branch [$root branches] { + $lod blockedby $branch + $branch possibleparents + if {[$branch haschild]} continue + $branch countasbranch + } + + foreach tag [$root tags] { + $lod blockedby $tag + $tag possibleparents + $tag countastag + } + + set root [$root child] + } + } + + return + } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hastypeinfo no ; # no type introspection + pragma -hasinfo no ; # no object introspection + pragma -hastypemethods no ; # type is not relevant. + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs { + namespace export file + namespace eval file { + # Import not required, already a child namespace. + # namespace import ::vc::fossil::import::cvs::file::rev + # namespace import ::vc::fossil::import::cvs::file::sym + namespace import ::vc::tools::misc::* + namespace import ::vc::tools::trouble + namespace import ::vc::tools::log + namespace import ::vc::fossil::import::cvs::state + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::file 1.0 +return
Added tools/cvs2fossil/lib/c2f_flodmgr.tcl version [755aedadae]
@@ -1,1 +1,57 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## Lines of Development in a file (Symbols, and the trunk). + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::file::lodmgr { + # # ## ### ##### ######## ############# + ## Public API + + constructor {} { + return + } + + # # ## ### ##### ######## ############# + ## State + + # # ## ### ##### ######## ############# + ## Internal methods + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hastypeinfo no ; # no type introspection + pragma -hasinfo no ; # no object introspection + pragma -hastypemethods no ; # type is not relevant. + pragma -simpledispatch yes ; # simple fast dispatch + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::file { + namespace export lodmgr +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::file::lodmgr 1.0 +return
Added tools/cvs2fossil/lib/c2f_frev.tcl version [b685fd71ec]
@@ -1,1 +1,531 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## Revisions per file. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require vc::tools::misc ; # Text formatting +package require vc::fossil::import::cvs::state ; # State storage. + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::file::rev { + # # ## ### ##### ######## ############# + ## Public API + + constructor {revnr date state thefile} { + set myrevnr $revnr + set mydate $date + set myorigdate $date + set mystate $state + set myfile $thefile + return + } + + method defid {} { + set myid [incr myidcounter] + return + } + + method id {} { return $myid } + + # Basic pieces ________________________ + + method hasmeta {} { return [expr {$mymetaid ne ""}] } + method hastext {} { + struct::list assign $mytext s e + return [expr {$s <= $e}] + } + + method setmeta {meta} { set mymetaid $meta ; return } + method settext {text} { set mytext $text ; return } + method setlod {lod} { set mylod $lod ; return } + + method revnr {} { return $myrevnr } + method state {} { return $mystate } + method lod {} { return $mylod } + method date {} { return $mydate } + + method isneeded {} { + if {$myoperation ne "nothing"} {return 1} + if {$myrevnr ne "1.1"} {return 1} + if {![$mylod istrunk]} {return 1} + if {![llength $mybranches]} {return 1} + set firstbranch [lindex $mybranches 0] + if {![$firstbranch haschild]} {return 1} + if {$myisondefaultbranch} {return 1} + + # FIX: This message will not match if the RCS file was renamed + # manually after it was created. + + set gen "file [file tail [$myfile usrpath]] was initially added on branch [$firstbranch name]." + set log [$myfile commitmessageof $mymetaid] + + return [expr {$log ne $gen}] + } + + method isneededbranchdel {} { + if {$myparentbranch eq ""} {return 1} ; # not first on a branch, needed + set base [$myparentbranch parent] + if {$base eq ""} {return 1} ; # branch has parent lod, needed + if {[$self LODLength] < 2} {return 1} ; # our lod contains only ourselves, needed. + if {$myoperation ne "delete"} {return 1} ; # Not a deletion, needed + if {[llength $mytags]} {return 1} ; # Have tags, needed + if {[llength $mybranches]} {return 1} ; # Have other branches, needed + if {abs($mydate - [$base date]) > 2} {return 1} ; # Next rev > 2 seconds apart, needed + + # FIXME: This message will not match if the RCS file was + # renamed manually after it was created. + + set qfile [string map { + . \\. ? \\? * \\* \\ \\\\ + \\+ ^ \\^ $ \\$ + \[ \\\[ \] \\\] ( \\( ) \\) \{ \\\{ \} \\\} + } [file tail [$myfile usrpath]]] + set pattern "file $qfile was added on branch .* on \\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}( \[+-\]\\d{4})?" + set log [$myfile commitmessageof $mymetaid] + + # Not the special message, needed + if {![regexp -- $pattern $log]} {return 1} + + # This is an unneeded initial branch delete. + return 0 + } + + method LODLength {} { + set n 1 ; # count self + set rev $mychild + while {$rev ne ""} { + incr n + set rev [$rev child] + } + return $n + } + + # Basic parent/child linkage __________ + + method hasparent {} { return [expr {$myparent ne ""}] } + method haschild {} { return [expr {$mychild ne ""}] } + + method setparent {parent} { + if {$myparent ne ""} { trouble internal "Parent already defined" } + set myparent $parent + return + } + + method cutfromparent {} { set myparent "" ; return } + method cutfromchild {} { set mychild "" ; return } + + method setchild {child} { + if {$mychild ne ""} { trouble internal "Child already defined" } + set mychild $child + return + } + + method changeparent {parent} { set myparent $parent ; return } + method changechild {child} { set mychild $child ; return } + + method parent {} { return $myparent } + method child {} { return $mychild } + + # Branch linkage ______________________ + + method setparentbranch {branch} { + if {$myparentbranch ne ""} { trouble internal "Branch parent already defined" } + set myparentbranch $branch + return + } + + method hasparentbranch {} { return [expr {$myparentbranch ne ""}] } + method hasbranches {} { return [llength $mybranches] } + + method parentbranch {} { return $myparentbranch } + method branches {} { return $mybranches } + + method addbranch {branch} { + lappend mybranches $branch + return + } + + method addchildonbranch {child} { + lappend mybranchchildren $child + return + } + + method cutfromparentbranch {} { set myparentbranch "" ; return } + + method removebranch {branch} { + ldelete mybranches $branch + return + } + + method removechildonbranch {rev} { + ldelete mybranchchildren $rev + return + } + + method sortbranches {} { + # Pass 2: CollectRev + + if {[llength $mybranches] < 2} return + + # Sort the branches spawned by this revision in creation + # order. To help in this our file gave all branches a position + # id, in order of their definition by the RCS archive. + # + # The creation order is (apparently) the reverse of the + # definition order. (If a branch is created then deleted, a + # later branch can be assigned the recycled branch number; + # therefore branch numbers are not an indication of creation + # order.) + + set tmp {} + foreach branch $mybranches { + lappend tmp [list $branch [$branch position]] + } + + set mybranches {} + foreach item [lsort -index 1 -decreasing $tmp] { + struct::list assign $item branch position + lappend mybranches $branch + } + return + } + + method movebranchesto {rev} { + set revlod [$rev lod] + foreach branch $mybranches { + $rev addbranch $branch + $branch setparent $rev + $branch setlod $revlod + } + foreach branchrev $mybranchchildren { + $rev addchildonbranch $branchrev + $branchrev cutfromparent + $branchrev setparent $rev + } + set mybranches {} + set mybranchchildren {} + return + } + + method removeallbranches {} { + set mybranches {} + set mybranchchildren {} + return + } + + # Tag linkage _________________________ + + method addtag {tag} { + lappend mytags $tag + return + } + + method tags {} { return $mytags } + + method removealltags {} { + set mytags {} + return + } + + method movetagsto {rev} { + set revlod [$rev lod] + foreach tag $mytags { + $rev addtag $tag + $tag settagrev $rev + $tag setlod $revlod + } + set mytags {} + return + } + + # general symbol operations ___________ + + method movesymbolsto {rev} { + # Move the tags and branches attached to this revision to the + # destination and fix all pointers. + + $self movetagsto $rev + $self movebranchesto $rev + return + } + + # Derived stuff _______________________ + + method determineoperation {} { + # Look at the state of both this revision and its parent to + # determine the type opf operation which was performed (add, + # modify, delete, none). + # + # The important information is dead vs not-dead for both, + # giving rise to four possible types. + + set sdead [expr {$mystate eq "dead"}] + set pdead [expr {$myparent eq "" || [$myparent state] eq "dead"}] + + set myoperation $myopstate([list $pdead $sdead]) + return + } + + method operation {} { return $myoperation } + method retype {x} { set myoperation $x ; return } + + method isondefaultbranch {} { return $myisondefaultbranch } + + method setondefaultbranch {x} { set myisondefaultbranch $x ; return } + + method setdefaultbranchchild {rev} { set mydbchild $rev ; return } + method setdefaultbranchparent {rev} { + set mydbparent $rev + + # Retype the revision (may change from 'add' to 'change'). + + set sdead [expr {$myoperation ne "change"}] + set pdead [expr {[$rev operation] ne "change"}] + set myoperation $myopstate([list $pdead $sdead]) + return + } + + method cutdefaultbranchparent {} { set mydbparent "" ; return } + method cutdefaultbranchchild {} { set mydbchild "" ; return } + + method defaultbranchchild {} { return $mydbchild } + method defaultbranchparent {} { return $mydbparent } + + method hasdefaultbranchchild {} { return [expr {$mydbchild ne ""}] } + method hasdefaultbranchparent {} { return [expr {$mydbparent ne ""}] } + + # # ## ### ##### ######## ############# + ## Type API + + typemethod istrunkrevnr {revnr} { + return [expr {[llength [split $revnr .]] == 2}] + } + + typemethod isbranchrevnr {revnr _ bv} { + if {[regexp $mybranchpattern $revnr -> head tail]} { + upvar 1 $bv branchnr + set branchnr ${head}$tail + return 1 + } + return 0 + } + + typemethod 2branchnr {revnr} { + # Input is a branch revision number, i.e. a revision number + # with an even number of components; for example '2.9.2.1' + # (never '2.9.2' nor '2.9.0.2'). The return value is the + # branch number (for example, '2.9.2'). For trunk revisions, + # like '3.4', we return the empty string. + + if {[$type istrunkrevnr $revnr]} { + return "" + } + return [join [lrange [split $revnr .] 0 end-1] .] + } + + typemethod 2branchparentrevnr {branchnr} { + # Chop the last segment off + return [join [lrange [split $branchnr .] 0 end-1] .] + } + + # # ## ### ##### ######## ############# + + method persist {} { + set fid [$myfile id] + set lod [$mylod id] + set op $myopcode($myoperation) + set idb $myisondefaultbranch + + struct::list assign $mytext coff end + set clen [expr {$end - $coff}] + + lappend map @P@ [expr { ($myparent eq "") ? "NULL" : [$myparent id] }] + lappend map @C@ [expr { ($mychild eq "") ? "NULL" : [$mychild id] }] + lappend map @DP [expr { ($mydbparent eq "") ? "NULL" : [$mydbparent id] }] + lappend map @DC [expr { ($mydbchild eq "") ? "NULL" : [$mydbchild id] }] + lappend map @BP [expr { ($myparentbranch eq "") ? "NULL" : [$myparentbranch id] }] + + set cmd { + INSERT INTO revision ( rid, fid, rev, lod, parent, child, isdefault, dbparent, dbchild, bparent, op, date, state, mid, coff, clen) + VALUES ($myid, $fid, $myrevnr, $lod, @P@, @C@, $idb, @DP, @DC, @BP , $op, $mydate, $mystate, $mymetaid, $coff, $clen); + } + + state transaction { + state run [string map $map $cmd] + + # And the branch children as well, for pass 5. + foreach bc $mybranchchildren { + set bcid [$bc id] + state run { + INSERT INTO revisionbranchchildren (rid, brid) + VALUES ($myid, $bcid); + } + } + } + return + } + + # # ## ### ##### ######## ############# + ## State + + # Persistent: myid - revision.rid + # myfile - revision.fid + # mylod - revision.lod + # myrevnr - revision.rev + # mydate - revision.date + # mystate - revision.state + # mymetaid - revision.mid + # mytext - revision.{cs,cl} + # myparent - revision.parent + # mychild - revision.child + # myparentbranch - revision.bparent + # myoperation - revision.op + # myisondefaultbranch - revision.isdefault + # mydbparent - revision.dbparent + # mydbchild - revision.dbchild + + + typevariable mybranchpattern {^((?:\d+\.\d+\.)+)(?:0\.)?(\d+)$} + # First a nonzero even number of digit groups with trailing dot + # CVS then sticks an extra 0 in here; RCS does not. + # And the last digit group. + + typevariable myidcounter 0 ; # Counter for revision ids. + variable myid {} ; # Revision id. + + variable myrevnr {} ; # Revision number of the revision. + variable mydate {} ; # Timestamp of the revision, seconds since epoch + variable myorigdate {} ; # Original unmodified timestamp. + variable mystate {} ; # State of the revision. + variable myfile {} ; # Ref to the file object the revision belongs to. + variable mytext {} ; # Range of the (delta) text for this revision in the file. + variable mymetaid {} ; # Id of the meta data group the revision + # belongs to. This is later used to put + # the file revisions into preliminary + # changesets (aka project revisions). + # This id encodes 4 pieces of data, + # namely: the project and branch the + # revision was committed to, the author + # who did the commit, and the message + # used. + variable mylod {} ; # Reference to the line-of-development + # object the revision belongs to. An + # alternative idiom would be to call it + # the branch the revision is on. This + # reference is to a project-level object + # (symbol or trunk). + + # Basic parent/child linkage (lines of development) + + variable myparent {} ; # Ref to parent revision object. Link required because of + # ; # 'cvsadmin -o', which can create arbitrary gaps in the + # ; # numbering sequence. This is in the same line of development + # ; # Note: For the first revision on a branch the revision + # ; # it was spawned from is the parent. Only the root revision + # ; # of myfile's revision tree has nothing set here. + # ; # + + variable mychild {} ; # Ref to the primary child revision object, i.e. the next + # ; # revision in the same line of development. + + # Branch linkage ____________________ + + variable mybranches {} ; # List of the branches (objs) spawned by this revision. + variable myparentbranch {} ; # For the first revision on a branch the relevant + # ; # branch object. This also allows us to determine if + # ; # myparent is in the same LOD, or the revision the + # ; # branch spawned from. + + # List of the revision objects of the first commits on any + # branches spawned by this revision on which commits occurred. + # This dependency is kept explicitly because otherwise a + # revision-only topological sort would miss the dependency that + # exists via -> mybranches. + + variable mybranchchildren {} ; # List of the revisions (objs) which are the first + # ; # commits on any of the branches spawned from this + # ; # revision. The dependency is kept explicitly to + # ; # ensure that a revision-only topological sort will + # ; # not miss it, as it otherwise exists only via + # ; # mybranches. + + # Tag linkage ________________________ + + variable mytags {} ; # List of tags (objs) associated with this revision. + + # More derived data + + variable myoperation {} ; # One of 'add', 'change', 'delete', or + # 'nothing'. Derived from our and + # its parent's state. + variable myisondefaultbranch 0 ; # Boolean flag, set if the + # revision is on the non-trunk + # default branch, aka vendor + # branch. + variable mydbparent {} ; # Reference to the last revision + # on the vendor branch if this is + # the primary child of the + # regular root. + variable mydbchild {} ; # Reference to the primary child + # of the regular root if this is + # the last revision on the vendor + # branch. + + # dead(self) x dead(parent) -> operation + typevariable myopstate -array { + {0 0} change + {0 1} delete + {1 0} add + {1 1} nothing + } + + typemethod getopcodes {} { + foreach {id name} [state run { + SELECT oid, name FROM optype; + }] { set myopcode($name) $id } + return + } + + typevariable myopcode -array {} + + # # ## ### ##### ######## ############# + ## Internal methods + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hastypeinfo no ; # no type introspection + pragma -hasinfo no ; # no object introspection + pragma -simpledispatch yes ; # simple fast dispatch + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::file { + namespace export rev + namespace eval rev { + namespace import ::vc::tools::misc::* + namespace import ::vc::fossil::import::cvs::state + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::file::rev 1.0 +return
Added tools/cvs2fossil/lib/c2f_fsym.tcl version [31fcf57a52]
@@ -1,1 +1,297 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## Symbols (Tags, Branches) per file. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require vc::tools::trouble ; # Error reporting. +package require vc::fossil::import::cvs::file::rev ; # CVS per file revisions. +package require vc::fossil::import::cvs::state ; # State storage. + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::file::sym { + # # ## ### ##### ######## ############# + ## Public API + + constructor {symtype nr symbol file} { + set myfile $file + set mytype $symtype + set mynr $nr + set mysymbol $symbol + + switch -exact -- $mytype { + branch { SetupBranch } + tag { } + default { trouble internal "Bad symbol type '$mytype'" } + } + return + } + + method defid {} { + set myid [incr myidcounter] + return + } + + method fid {} { return $myid } + method symbol {} { return $mysymbol } + + # Symbol acessor methods. + + delegate method name to mysymbol + delegate method id to mysymbol + + # Symbol aggregation methods + + delegate method countasbranch to mysymbol + delegate method countastag to mysymbol + delegate method countacommit to mysymbol + + method blockedby {fsymbol} { + $mysymbol blockedby [$fsymbol symbol] + return + } + + method possibleparents {} { + switch -exact -- $mytype { + branch { $self BranchParents } + tag { $self TagParents } + } + return + } + + method BranchParents {} { + # The "obvious" parent of a branch is the branch holding the + # revision spawning the branch. Any other branches that are + # rooted at the same revision and were committed earlier than + # the branch are also possible parents. + + $mysymbol possibleparent [[$mybranchparent lod] symbol] + + foreach branch [$mybranchparent branches] { + # A branch cannot be its own parent. Nor can a branch + # created after this one be its parent. This means that we + # can abort the loop when we have reached ourselves in the + # list of branches. Here the order of file::rev.mybranches + # comes into play, as created by file::rev::sortbranches. + + if {$branch eq $self} break + $mysymbol possibleparent [$branch symbol] + } + return + } + + method TagParents {} { + # The "obvious" parent of a tag is the branch holding the + # revision spawning the tag. Branches that are spawned by the + # same revision are also possible parents. + + $mysymbol possibleparent [[$mytagrev lod] symbol] + + foreach branch [$mytagrev branches] { + $mysymbol possibleparent [$branch symbol] + } + return + } + + # + + method istrunk {} { return 0 } + + # Branch acessor methods. + + method setchildrevnr {revnr} { + if {$mybranchchildrevnr ne ""} { trouble internal "Child already defined" } + set mybranchchildrevnr $revnr + return + } + + method setposition {n} { set mybranchposition $n ; return } + method setparent {rev} { set mybranchparent $rev ; return } + method setchild {rev} { set mybranchchild $rev ; return } + method cutchild {} { set mybranchchild "" ; return } + + method branchnr {} { return $mynr } + method parentrevnr {} { return $mybranchparentrevnr } + method childrevnr {} { return $mybranchchildrevnr } + method haschildrev {} { return [expr {$mybranchchildrevnr ne ""}] } + method haschild {} { return [expr {$mybranchchild ne ""}] } + method parent {} { return $mybranchparent } + method child {} { return $mybranchchild } + method position {} { return $mybranchposition } + + # Tag acessor methods. + + method tagrevnr {} { return $mynr } + method settagrev {rev} {set mytagrev $rev ; return } + + # Derived information + + method lod {} { return $mylod } + + method setlod {lod} { + set mylod $lod + $self checklod + return + } + + method checklod {} { + # Consistency check. The symbol's line-of-development has to + # be same as the line-of-development of its source (parent + # revision of a branch, revision of a tag itself). + + switch -exact -- $mytype { + branch { set slod [$mybranchparent lod] } + tag { set slod [$mytagrev lod] } + } + + if {$mylod ne $slod} { + trouble fatal "For $mytype [$mysymbol name]: LOD conflict with source, '[$mylod name]' vs. '[$slod name]'" + return + } + return + } + + # # ## ### ##### ######## ############# + + method persist {} { + # Save the information we need after the collection pass. + + set fid [$myfile id] + set sid [$mysymbol id] + set lod [$mylod id] + + switch -exact -- $mytype { + tag { + set rid [$mytagrev id] + state transaction { + state run { + INSERT INTO tag ( tid, fid, lod, sid, rev) + VALUES ($myid, $fid, $lod, $sid, $rid); + } + } + } + branch { + lappend map @F@ [expr { ($mybranchchild eq "") ? "NULL" : [$mybranchchild id] }] + + set rid [$mybranchparent id] + set cmd { + INSERT INTO branch ( bid, fid, lod, sid, root, first, bra, pos ) + VALUES ($myid, $fid, $lod, $sid, $rid, @F@, $mynr, $mybranchposition); + } + state transaction { + state run [string map $map $cmd] + } + } + } + + return + } + + # # ## ### ##### ######## ############# + ## State + + # Persistent: + # Tag: myid - tag.tid + # myfile - tag.fid + # mylod - tag.lod + # mysymbol - tag.sid + # mytagrev - tag.rev + # + # Branch: myid - branch.bid + # myfile - branch.fid + # mylod - branch.lod + # mysymbol - branch.sid + # mybranchparent - branch.root + # mybranchchild - branch.first + # mynr - branch.bra + + typevariable myidcounter 0 ; # Counter for symbol ids. + variable myid {} ; # Symbol id. + + ## Basic, all symbols _________________ + + variable myfile {} ; # Reference to the file the symbol is in. + variable mytype {} ; # Symbol type, 'tag', or 'branch'. + variable mynr {} ; # Revision number of a 'tag', branch number + # of a 'branch'. + variable mysymbol {} ; # Reference to the symbol object of this + # symbol at the project level. + variable mylod {} ; # Reference to the line-of-development + # object the symbol belongs to. An + # alternative idiom would be to call it the + # branch the symbol is on. This reference + # is to a project-level object (symbol or + # trunk). + + ## Branch symbols _____________________ + + variable mybranchparentrevnr {} ; # The number of the parent + # revision, derived from our + # branch number (mynr). + variable mybranchparent {} ; # Reference to the revision + # (object) which spawns the + # branch. + variable mybranchchildrevnr {} ; # Number of the first revision + # committed on this branch. + variable mybranchchild {} ; # Reference to the revision + # (object) first committed on + # this branch. + variable mybranchposition {} ; # Relative id of the branch in + # the file, to sort into + # creation order. + + ## Tag symbols ________________________ + + variable mytagrev {} ; # Reference to the revision object the tag + # is on, identified by 'mynr'. + + # ... nothing special ... (only mynr, see basic) + + # # ## ### ##### ######## ############# + ## Internal methods + + proc SetupBranch {} { + upvar 1 mybranchparentrevnr mybranchparentrevnr mynr mynr + set mybranchparentrevnr [rev 2branchparentrevnr $mynr] + return + } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hastypeinfo no ; # no type introspection + pragma -hasinfo no ; # no object introspection + pragma -hastypemethods no ; # type is not relevant. + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::file { + namespace export sym + namespace eval sym { + namespace import ::vc::fossil::import::cvs::file::rev + namespace import ::vc::fossil::import::cvs::state + namespace import ::vc::tools::trouble + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::file::sym 1.0 +return
Added tools/cvs2fossil/lib/c2f_ftrunk.tcl version [4dd74e0101]
@@ -1,1 +1,57 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## Trunk, the special main line of development in a file. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::file::trunk { + # # ## ### ##### ######## ############# + ## Public API + + constructor {} { + return + } + + # # ## ### ##### ######## ############# + ## State + + # # ## ### ##### ######## ############# + ## Internal methods + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hastypeinfo no ; # no type introspection + pragma -hasinfo no ; # no object introspection + pragma -hastypemethods no ; # type is not relevant. + pragma -simpledispatch yes ; # simple fast dispatch + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::file { + namespace export trunk +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::file::trunk 1.0 +return
Added tools/cvs2fossil/lib/c2f_integrity.tcl version [f5cf3c5637]
@@ -1,1 +1,321 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## This package holds a number of integrity checks done on the +## persistent state. This is used by the passes II and IV. + +# # ## ### ##### ######## ############# ##################### +## 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::state ; # State storage. + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::integrity { + # # ## ### ##### ######## ############# + ## Public API + + typemethod strict {} { + set n 0 + AllButMeta + Meta + return + } + + typemethod metarelaxed {} { + set n 0 + AllButMeta + return + } + + # # ## ### ##### ######## ############# + ## Internal methods + + proc AllButMeta {} { + # This code performs a number of paranoid checks of the + # database, searching for inconsistent cross-references. + log write 4 integrity {Check database consistency} + + upvar 1 n n ; # Counter for the checks (we print an id before + # the main label). + + # Find all revisions which disagree with their line of + # development about the project they are owned by. + Check \ + {Revisions and their LODs have to be in the same project} \ + {disagrees with its LOD about owning project} { + SELECT F.name, R.rev + FROM revision R, file F, symbol S + WHERE R.fid = F.fid + AND R.lod = S.sid + AND F.pid != S.pid + ; + } + # Find all revisions which disgree with their meta data about + # the project they are owned by. + Check \ + {Revisions and their meta data have to be in the same project} \ + {disagrees with its meta data about owning project} { + SELECT F.name, R.rev + FROM revision R, file F, meta M + WHERE R.fid = F.fid + AND R.mid = M.mid + AND F.pid != M.pid + ; + } + # Find all revisions with a primary child which disagrees + # about the file they belong to. + Check \ + {Revisions and their primary children have to be in the same file} \ + {disagrees with its primary child about the owning file} { + SELECT F.name, R.rev + FROM revision R, revision C, file F + WHERE R.fid = F.fid + AND R.child IS NOT NULL + AND R.child = C.rid + AND C.fid != R.fid + ; + } + + # Find all revisions with a branch parent symbol whose parent + # disagrees about the file they belong to. + Check \ + {Revisions and their branch children have to be in the same file} \ + {at the beginning of its branch and its parent disagree about the owning file} { + SELECT F.name, R.rev + FROM revision R, revision P, file F + WHERE R.fid = F.fid + AND R.bparent IS NOT NULL + AND R.parent = P.rid + AND R.fid != P.fid + ; + } + # Find all revisions with a non-NTDB child which disagrees + # about the file they belong to. + Check \ + {Revisions and their non-NTDB children have to be in the same file} \ + {disagrees with its non-NTDB child about the owning file} { + SELECT F.name, R.rev + FROM revision R, revision C, file F + WHERE R.fid = F.fid + AND R.dbchild IS NOT NULL + AND R.dbchild = C.rid + AND C.fid != R.fid + ; + } + # Find all revisions which have a primary child, but the child + # does not have them as parent. + Check \ + {Revisions have to be parents of their primary children} \ + {is not the parent of its primary child} { + SELECT F.name, R.rev + FROM revision R, revision C, file F + WHERE R.fid = F.fid + AND R.child IS NOT NULL + AND R.child = C.rid + AND C.parent != R.rid + ; + } + # Find all revisions which have a primrary child, but the + # child has a branch parent symbol making them brach starters. + Check \ + {Primary children of revisions must not start branches} \ + {is parent of a primary child which is the beginning of a branch} { + SELECT F.name, R.rev + FROM revision R, revision C, file F + WHERE R.fid = F.fid + AND R.child IS NOT NULL + AND R.child = C.rid + AND C.bparent IS NOT NULL + ; + } + # Find all revisions without branch parent symbol which have a + # parent, but the parent does not have them as primary child. + Check \ + {Revisions have to be primary children of their parents, if any} \ + {is not the child of its parent} { + SELECT F.name, R.rev + FROM revision R, revision P, file F + WHERE R.fid = F.fid + AND R.bparent IS NULL + AND R.parent IS NOT NULL + AND R.parent = P.rid + AND P.child != R.rid + ; + } + # Find all revisions with a branch parent symbol which do not + # have a parent. + Check \ + {Branch starting revisions have to have a parent} \ + {at the beginning of its branch has no parent} { + SELECT F.name, R.rev + FROM revision R, file F + WHERE R.fid = F.fid + AND R.bparent IS NOT NULL + AND R.parent IS NULL + ; + } + # Find all revisions with a branch parent symbol whose parent + # has them as primary child. + Check \ + {Branch starting revisions must not be primary children of their parents} \ + {at the beginning of its branch is the primary child of its parent} { + SELECT F.name, R.rev + FROM revision R, revision P, file F + WHERE R.fid = F.fid + AND R.bparent IS NOT NULL + AND R.parent IS NOT NULL + AND R.parent = P.rid + AND P.child = R.rid + ; + } + # Find all revisions with a non-NTDB child which are not on + # the NTDB. + Check \ + {NTDB to trunk transition has to begin on NTDB} \ + {has a non-NTDB child, yet is not on the NTDB} { + SELECT F.name, R.rev + FROM revision R, file F + WHERE R.fid = F.fid + AND R.dbchild IS NOT NULL + AND NOT R.isdefault + ; + } + # Find all revisions with a NTDB parent which are on the NTDB. + Check \ + {NTDB to trunk transition has to end on non-NTDB} \ + {has a NTDB parent, yet is on the NTDB} { + SELECT F.name, R.rev + FROM revision R, file F + WHERE R.fid = F.fid + AND R.dbparent IS NOT NULL + AND R.isdefault + ; + } + # Find all revisions with a child which disagrees about the + # line of development they belong to. + Check \ + {Revisions and their primary children have to be in the same LOD} \ + {and its primary child disagree about their LOD} { + SELECT F.name, R.rev + FROM revision R, revision C, file F + WHERE R.fid = F.fid + AND R.child IS NOT NULL + AND R.child = C.rid + AND C.lod != R.lod + ; + } + # Find all revisions with a non-NTDB child which agrees about + # the line of development they belong to. + Check \ + {NTDB and trunk revisions have to be in different LODs} \ + {on NTDB and its non-NTDB child wrongly agree about their LOD} { + SELECT F.name, R.rev + FROM revision R, revision C, file F + WHERE R.fid = F.fid + AND R.dbchild IS NOT NULL + AND R.dbchild = C.rid + AND C.lod = R.lod + ; + } + # Find all revisions with a branch parent symbol which is not + # their LOD. + Check \ + {Branch starting revisions have to have their LOD as branch parent symbol} \ + {at the beginning of its branch does not have the branch symbol as its LOD} { + SELECT F.name, R.rev + FROM revision R, file F + WHERE R.fid = F.fid + AND R.bparent IS NOT NULL + AND R.lod != R.bparent + ; + } + # Find all revisions with a branch parent symbol whose parent + # is in the same line of development. + Check \ + {Revisions and their branch children have to be in different LODs} \ + {at the beginning of its branch and its parent wrongly agree about their LOD} { + SELECT F.name, R.rev + FROM revision R, revision P, file F + WHERE R.fid = F.fid + AND R.bparent IS NOT NULL + AND R.parent = P.rid + AND R.lod = P.lod + ; + } + return + } + + proc Meta {} { + # This code performs a number of paranoid checks of the + # database, searching for inconsistent cross-references. + log write 4 integrity {Check database consistency} + + upvar 1 n n ; # Counter for the checks (we print an id before + # the main label). + + # Find all revisions which disgree with their meta data about + # the branch/line of development they belong to. + Check \ + {Revisions and their meta data have to be in the same LOD} \ + {disagrees with its meta data about owning LOD} { + SELECT F.name, R.rev + FROM revision R, meta M, file F + WHERE R.mid = M.mid + AND R.lod != M.bid + AND R.fid = F.fid + ; + } + return + } + + proc Check {header label sql} { + upvar 1 n n + set ok 1 + foreach {fname revnr} [state run $sql] { + set ok 0 + trouble fatal "$fname <$revnr> $label" + } + log write 5 integrity "\[[format %02d [incr n]]\] [expr {$ok ? "Ok " : "Failed"}] ... $header" + return + } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs { + namespace export integrity + namespace eval integrity { + namespace import ::vc::fossil::import::cvs::state + namespace import ::vc::tools::trouble + namespace import ::vc::tools::log + log register integrity + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::integrity 1.0 +return
Added tools/cvs2fossil/lib/c2f_option.tcl version [d7008b5e1a]
@@ -1,1 +1,230 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## Option database, processes the command line. Note that not all of +## the option information is stored here. Parts are propagated to +## other pieces of the system and handled there, via option +## delegation + +# # ## ### ##### ######## ############# ##################### +## 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::tools::misc ; # Misc. path reformatting. +package require vc::fossil::import::cvs::pass ; # Pass management +package require vc::fossil::import::cvs::pass::collar ; # Pass I. +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 + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::option { + # # ## ### ##### ######## ############# + ## Public API, Options. + + # --help, --help-passes, -h + # --version + # -p, --pass, --passes + # --ignore-conflicting-attics + # --project + # -v, --verbose + # -q, --quiet + # --state (conversion status, ala config.cache) + # --trunk-only + # --exclude, --force-tag, --force-branch + + # -o, --output + # --dry-run + # --force-branch RE + # --force-tag RE + # --symbol-transform RE:XX + + # # ## ### ##### ######## ############# + ## Public API, Methods + + typemethod process {arguments} { + # Syntax of arguments: ?option ?value?...? /path/to/cvs/repository + + while {[IsOption arguments -> option]} { + switch -exact -- $option { + -h - + --help { PrintHelp ; exit 0 } + --help-passes { pass help ; exit 0 } + --version { PrintVersion ; exit 0 } + -p - + --pass - + --passes { pass select [Value arguments] } + --ignore-conflicting-attics { collar ignore_conflicting_attics } + --project { repository add [Value arguments] } + -v - + --verbose { log verbose } + -q - + --quiet { log quiet } + --state { state use [Value arguments] } + --trunk-only { repository trunkonly! } + --exclude { project::sym exclude [Value arguments] } + --force-tag { project::sym forcetag [Value arguments] } + --force-branch { project::sym forcebranch [Value arguments] } + default { + Usage $badoption$option\n$gethelp + } + } + } + + if {[llength $arguments] > 1} Usage + if {[llength $arguments] < 1} { Usage $nocvs } + repository base [striptrailingslash [lindex $arguments 0]] + + Validate + return + } + + # # ## ### ##### ######## ############# + ## Internal methods, printing information. + + proc PrintHelp {} { + global argv0 + trouble info "Usage: $argv0 $usage" + trouble info "" + trouble info " Information options" + trouble info "" + trouble info " -h, --help Print this message and exit with success" + trouble info " --help-passes Print list of passes and exit with success" + trouble info " --version Print version number of $argv0" + trouble info " -v, --verbose Increase application's verbosity" + trouble info " -q, --quiet Decrease application's verbosity" + trouble info "" + trouble info " Conversion control options" + trouble info "" + trouble info " -p, --pass PASS Run only the specified conversion pass" + trouble info " -p, --passes ?START?:?END? Run only the passes START through END," + trouble info " inclusive." + trouble info "" + trouble info " Passes are specified by name." + trouble info "" + trouble info " --ignore-conflicting-attics" + trouble info " Prevent abort when conflicting archives" + trouble info " were found in both regular and Attic." + trouble info "" + trouble info " --state PATH Save state to the specified file, and" + trouble info " load state of previous runs from it too." + trouble info "" + trouble info " --exclude ?PROJECT:?SYMBOL Exclude the named symbol from all or" + trouble info " just the specified project. Both project" + trouble info " and symbol names are glob patterns." + trouble info "" + trouble info " --force-tag ?PROJECT:?SYMBOL" + trouble info " Force the named symbol from all or just" + trouble info " the specified project to be converted as" + trouble info " tag. Both project and symbol names are" + trouble info " glob patterns." + trouble info "" + trouble info " --force-branch ?PROJECT:?SYMBOL" + trouble info " Force the named symbol from all or just" + trouble info " the specified project to be converted as" + trouble info " branch. Both project and symbol names" + trouble info " are glob patterns." + trouble info "" + + # --project, --cache + # ... + return + } + + proc PrintVersion {} { + global argv0 + set v [package require vc::fossil::import::cvs] + trouble info "$argv0 v$v" + return + } + + proc Usage {{text {}}} { + global argv0 + trouble fatal "Usage: $argv0 $usage" + if {$text ne ""} { trouble fatal "$text" } + exit 1 + } + + # # ## ### ##### ######## ############# + ## Internal methods, command line processing + + typevariable usage "?option ?value?...? cvs-repository-path" + typevariable nocvs " The cvs-repository-path is missing." + typevariable badoption " Bad option " + typevariable gethelp " Use --help to get help." + + proc IsOption {av _ ov} { + upvar 1 $av arguments $ov option + set candidate [lindex $arguments 0] + if {![string match -* $candidate]} {return 0} + set option $candidate + set arguments [lrange $arguments 1 end] + return 1 + } + + proc Value {av} { + upvar 1 $av arguments + set v [lindex $arguments 0] + set arguments [lrange $arguments 1 end] + return $v + } + + # # ## ### ##### ######## ############# + ## Internal methods, state validation + + proc Validate {} { + # Prevent in-depth validation if the options were already bad. + trouble abort? + + repository validate + state setup + + trouble abort? + return + } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs { + namespace export option + namespace eval option { + namespace import ::vc::tools::misc::striptrailingslash + namespace import ::vc::fossil::import::cvs::pass + namespace import ::vc::fossil::import::cvs::pass::collar + 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 + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::option 1.0 +return
Added tools/cvs2fossil/lib/c2f_pass.tcl version [6faa3b2682]
@@ -1,1 +1,213 @@ +## -*- 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 manager. All passes register here, with code, description, and +## callbacks (... setup, run, finalize). Option processing and help +## query this manager to dynamically create the relevant texts. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require vc::fossil::import::cvs::state ; # State storage +package require vc::tools::misc ; # Text formatting +package require vc::tools::trouble ; # Error reporting. +package require vc::tools::log ; # User feedback. +package require struct::list ; # Portable lassign + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::pass { + # # ## ### ##### ######## ############# + ## Public API, Methods (Setup, query) + + typemethod define {name description command} { + if {[info exists mydesc($name)]} { + trouble internal "Multiple definitions for pass code '$name'" + } + lappend mypasses $name + set mydesc($name) $description + set mycmd($name) $command + return + } + + typemethod help {} { + trouble info "" + trouble info "Conversion passes:" + trouble info "" + set n 0 + + set clen [max [struct::list map $mypasses {string length}]] + set cfmt %-${clen}s + set nfmt %[string length [llength $mypasses]]s + + foreach code $mypasses { + trouble info " [format $nfmt $n]: [format $cfmt $code] : $mydesc($code)" + incr n + } + trouble info "" + return + } + + # # ## ### ##### ######## ############# + ## Public API, Methods (Execution) + + typemethod select {passdef} { + set pl [split $passdef :] + if {[llength $pl] > 2} { + trouble fatal "Bad pass definition '$passdef'" + trouble fatal "Expected at most one ':'" + } elseif {[llength $pl] == 2} { + struct::list assign $pl start end + + if {($start eq "") && ($end eq "")} { + trouble fatal "Specify at least one of start- or end-pass" + set ok 0 + } else { + set ok 1 + Ok? $start start ok + Ok? $end end ok + } + + if {$ok} { + set mystart [Convert $start 0] + set myend [Convert $end end] + if {$mystart > $myend} { + trouble fatal "Start pass is after end pass" + } + } + } elseif {[llength $pl] < 2} { + set start [lindex $pl 0] + Ok? $start "" __dummy__ 0 + set mystart [Id $start] + set myend $mystart + } + } + + typemethod run {} { + if {$mystart < 0} {set mystart 0} + if {$myend < 0} {set myend [expr {[llength $mypasses] - 1}]} + + set skipped [lrange $mypasses 0 [expr {$mystart - 1}]] + set run [lrange $mypasses $mystart $myend] + set defered [lrange $mypasses [expr {$myend + 1}] end] + + foreach p $skipped { + log write 0 pass "Skip $p" + Call $p load + } + foreach p $run { + log write 0 pass "Setup $p" + Call $p setup + } + foreach p $run { + log write 0 pass "Begin $p" + Time $p [lindex [time {Call $p run} 1] 0] + log write 0 pass "Done $p" + trouble abort? + } + foreach p $defered { + log write 0 pass "Defer $p" + Call $p discard + } + + state release + ShowTimes + return + } + + proc Time {pass useconds} { + ::variable mytime + lappend mytime $pass $useconds + return + } + + proc ShowTimes {} { + ::variable mytime + foreach {pass useconds} $mytime { + set sec [format %8.2f [expr {double($useconds)/1e6}]] + log write 0 pass "$sec sec/$pass" + } + return + } + + # # ## ### ##### ######## ############# + ## Internal methods + + proc Ok? {code label ov {emptyok 1}} { + upvar 1 $ov ok + ::variable mydesc + if {$emptyok && ($code eq "")} return + if {[info exists mydesc($code)]} return + if {$label ne ""} {append label " "} + trouble fatal "Bad ${label}pass code $code" + set ok 0 + return + } + + proc Convert {code default} { + ::variable mypasses + return [expr {($code eq "") ? $default : [Id $code]}] + } + + proc Id {code} { + ::variable mypasses + return [lsearch -exact $mypasses $code] + } + + proc Call {code args} { + ::variable mycmd + set cmd $mycmd($code) + foreach a $args { lappend cmd $a } + eval $cmd + return + } + + # # ## ### ##### ######## ############# + ## Internal, state + + typevariable mypasses {} ; # List of registered passes (codes). + typevariable mydesc -array {} ; # Pass descriptions (one line). + typevariable mycmd -array {} ; # Pass callback command. + + typevariable mystart -1 + typevariable myend -1 + typevariable mytime {} ; # Timing data for each executed pass. + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs { + namespace export pass + namespace eval pass { + namespace import ::vc::fossil::import::cvs::state + namespace import ::vc::tools::misc::* + namespace import ::vc::tools::trouble + namespace import ::vc::tools::log + log register pass + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::pass 1.0 +return
Added tools/cvs2fossil/lib/c2f_pbreakacycle.tcl version [9a96d44941]
@@ -1,1 +1,101 @@ +## -*- 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 VIII. This is the final pass for breaking changeset dependency +## cycles. The two previous passes broke cycles covering revision and +## symbol changesets, respectively. This pass now breaks any remaining +## cycles each of which has to contain at least one revision and at +## least one symbol changeset. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require struct::list ; # Higher order list operations. +package require vc::tools::log ; # User feedback. +package require vc::fossil::import::cvs::cyclebreaker ; # Breaking dependency cycles. +package require vc::fossil::import::cvs::state ; # State storage. +package require vc::fossil::import::cvs::project::rev ; # Project level changesets + +# # ## ### ##### ######## ############# ##################### +## Register the pass with the management + +vc::fossil::import::cvs::pass define \ + BreakAllCsetCycles \ + {Break Remaining ChangeSet Dependency Cycles} \ + ::vc::fossil::import::cvs::pass::breakacycle + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::pass::breakacycle { + # # ## ### ##### ######## ############# + ## Public API + + typemethod setup {} { + # Define the names and structure of the persistent state of + # this pass. + return + } + + typemethod load {} { + # Pass manager interface. Executed to load data computed by + # this pass into memory when this pass is skipped instead of + # executed. + return + } + + typemethod run {} { + # Pass manager interface. Executed to perform the + # functionality of the pass. + 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. + return + } + + # # ## ### ##### ######## ############# + ## Internal methods + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::pass { + namespace export breakacycle + namespace eval breakacycle { + namespace import ::vc::fossil::import::cvs::cyclebreaker + namespace import ::vc::fossil::import::cvs::state + namespace eval project { + namespace import ::vc::fossil::import::cvs::project::rev + } + namespace import ::vc::tools::log + log register breakacycle + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::pass::breakacycle 1.0 +return
Added tools/cvs2fossil/lib/c2f_pbreakrcycle.tcl version [030100362a]
@@ -1,1 +1,141 @@ +## -*- 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 VI. This pass goes over the set of revision based changesets +## and breaks all dependency cycles they may be in. We need a +## dependency tree. Identical to pass VII, except for the selection of +## the changesets. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require struct::list ; # Higher order list operations. +package require vc::tools::log ; # User feedback. +package require vc::fossil::import::cvs::repository ; # Repository management. +package require vc::fossil::import::cvs::cyclebreaker ; # Breaking dependency cycles. +package require vc::fossil::import::cvs::state ; # State storage. +package require vc::fossil::import::cvs::project::rev ; # Project level changesets + +# # ## ### ##### ######## ############# ##################### +## Register the pass with the management + +vc::fossil::import::cvs::pass define \ + BreakRevCsetCycles \ + {Break Revision ChangeSet Dependency Cycles} \ + ::vc::fossil::import::cvs::pass::breakrcycle + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::pass::breakrcycle { + # # ## ### ##### ######## ############# + ## Public API + + typemethod setup {} { + # Define the names and structure of the persistent state of + # this pass. + + state reading revision + state reading changeset + state reading csrevision + + state writing csorder { + -- Commit order of changesets based on their dependencies + cid INTEGER NOT NULL REFERENCES changeset, + pos INTEGER NOT NULL, + UNIQUE (cid), + UNIQUE (pos) + } + return + } + + typemethod load {} { + # Pass manager interface. Executed to load data computed by + # this pass into memory when this pass is skipped instead of + # executed. + + state reading changeset + project::rev loadcounter + return + } + + typemethod run {} { + # Pass manager interface. Executed to perform the + # functionality of the pass. + + state transaction { + cyclebreaker run [struct::list filter [project::rev all] \ + [myproc IsByRevision]] \ + [myproc SaveOrder] + } + + repository printcsetstatistics + 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 csorder + return + } + + # # ## ### ##### ######## ############# + ## Internal methods + + proc IsByRevision {cset} { $cset byrevision } + + proc SaveOrder {at cset} { + set cid [$cset id] + + log write 4 breakrcycle "Comitting @ $at: <$cid>" + state run { + INSERT INTO csorder (cid, pos) + VALUES ($cid, $at) + } + # TODO: Write the project level changeset dependencies as well. + return + } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::pass { + namespace export breakrcycle + namespace eval breakrcycle { + namespace import ::vc::fossil::import::cvs::cyclebreaker + namespace import ::vc::fossil::import::cvs::repository + namespace import ::vc::fossil::import::cvs::state + namespace eval project { + namespace import ::vc::fossil::import::cvs::project::rev + } + namespace import ::vc::tools::log + log register breakrcycle + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::pass::breakrcycle 1.0 +return
Added tools/cvs2fossil/lib/c2f_pbreakscycle.tcl version [a1d5600281]
@@ -1,1 +1,112 @@ +## -*- 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 VII. This pass goes over the set of symbol based changesets +## and breaks all dependency cycles they may be in. We need a +## dependency tree. Identical to pass VI, except for the selection of +## the changesets. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require struct::list ; # Higher order list operations. +package require vc::fossil::import::cvs::cyclebreaker ; # Breaking dependency cycles. +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::rev ; # Project level changesets + +# # ## ### ##### ######## ############# ##################### +## Register the pass with the management + +vc::fossil::import::cvs::pass define \ + BreakSymCsetCycles \ + {Break Symbol ChangeSet Dependency Cycles} \ + ::vc::fossil::import::cvs::pass::breakscycle + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::pass::breakscycle { + # # ## ### ##### ######## ############# + ## Public API + + typemethod setup {} { + # Define the names and structure of the persistent state of + # this pass. + + state reading revision + state reading changeset + state reading csrevision + return + } + + typemethod load {} { + # Pass manager interface. Executed to load data computed by + # this pass into memory when this pass is skipped instead of + # executed. + return + } + + typemethod run {} { + # Pass manager interface. Executed to perform the + # functionality of the pass. + + state transaction { + cyclebreaker run [struct::list filter [project::rev all] \ + [myproc IsBySymbol]] + } + + repository printcsetstatistics + 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. + return + } + + # # ## ### ##### ######## ############# + ## Internal methods + + proc IsBySymbol {cset} { $cset bysymbol } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::pass { + namespace export breakscycle + namespace eval breakscycle { + namespace import ::vc::fossil::import::cvs::cyclebreaker + namespace import ::vc::fossil::import::cvs::repository + namespace import ::vc::fossil::import::cvs::state + namespace eval project { + namespace import ::vc::fossil::import::cvs::project::rev + } + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::pass::breakscycle 1.0 +return
Added tools/cvs2fossil/lib/c2f_pcollar.tcl version [32b24a90eb]
@@ -1,1 +1,266 @@ +## -*- 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 I. This pass scans the repository to import for RCS archives, +## and sorts and filters them into the declared projects, if any +## Without declared projects the whole repository is treated as a +## single project. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require fileutil::traverse ; # Directory traversal. +package require fileutil ; # File & path utilities. +package require vc::tools::trouble ; # Error reporting. +package require vc::tools::log ; # User feedback. +package require vc::fossil::import::cvs::pass ; # Pass management. +package require vc::fossil::import::cvs::repository ; # Repository management. +package require vc::fossil::import::cvs::state ; # State storage + +# # ## ### ##### ######## ############# ##################### +## Register the pass with the management + +vc::fossil::import::cvs::pass define \ + CollectAr \ + {Collect archives in repository} \ + ::vc::fossil::import::cvs::pass::collar + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::pass::collar { + # # ## ### ##### ######## ############# + ## Public API + + typemethod setup {} { + # Define names and structure of the persistent state of this + # pass. + + # We deal with repository projects, and the rcs archive files + # in the projects. + + # For the first, projects, we keep their names, which are + # their paths relative to the base directory of the whole + # repository. These have to be globally unique, i.e. no two + # projects can have the same name. + + # For the files we keep their names, which are their paths + # relative to the base directory of the whole project! These + # have to be unique within a project, however globally this + # does not hold, a name may occur several times, in different + # projects. We further store the user visible file name + # associated with the rcs archive. + + # Both projects and files are identified by globally unique + # integer ids, automatically assigned by the database. + + state writing project { + pid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE + } + state writing file { + fid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + pid INTEGER NOT NULL REFERENCES project, -- project the file belongs to + name TEXT NOT NULL, + visible TEXT NOT NULL, + exec INTEGER NOT NULL, -- boolean, 'file executable'. + UNIQUE (pid, name) -- file names are unique within a project + } + return + } + + typemethod load {} { + # Pass manager interface. Executed for all passes before the + # run passes, to load all data of their pass from the state, + # as if it had been computed by the pass itself. + + state reading project + state reading file + + repository load + return + } + + typemethod run {} { + # Pass manager interface. Executed to perform the + # functionality of the pass. + + set rbase [repository base?] + foreach project [repository projects] { + set base [file join $rbase [$project base]] + log write 1 collar "Scan $base" + + set traverse [fileutil::traverse %AUTO% $base \ + -prefilter [myproc FilterAtticSubdir $base]] + set n 0 + set r {} + + $traverse foreach path { + set rcs [fileutil::stripPath $base $path] + if {[IsCVSAdmin $rcs]} continue + if {![IsRCSArchive $path]} continue + + set usr [UserPath $rcs isattic] + if {[IsSuperceded $base $rcs $usr $isattic]} continue + + if { + [file exists $base/$usr] && + [file isdirectory $base/$usr] + } { + trouble fatal "Directory name conflicts with filename." + trouble fatal "Please remove or rename one of the following:" + trouble fatal " $base/$usr" + trouble fatal " $base/$rcs" + continue + } + + log write 4 collar "Found $rcs" + $project addfile $rcs $usr [file executable $rcs] + + incr n + if {[log verbosity?] < 4} { + log progress 0 collar $n {} + } + } + + $traverse destroy + } + + repository printstatistics + repository persist + + log write 1 collar "Scan 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 project + state discard file + return + } + + typemethod ignore_conflicting_attics {} { + set myignore 1 + return + } + + # # ## ### ##### ######## ############# + ## Internal methods + + typevariable myignore 0 + + proc FilterAtticSubdir {base path} { + # This command is used by the traverser to prevent it from + # scanning into subdirectories of an Attic. We get away with + # checking the immediate parent directory of the current path + # as our rejection means that deeper path do not occur. + + if {[file tail [file dirname $path]] eq "Attic"} { + set ad [fileutil::stripPath $base $path] + log write 1 collar "Directory $ad found in Attic, ignoring." + return 0 + } + return 1 + } + + proc IsRCSArchive {path} { + if {![string match *,v $path]} {return 0} + if {[fileutil::test $path fr msg]} {return 1} + trouble warn $msg + return 0 + } + + proc IsCVSAdmin {rcs} { + if {![string match CVSROOT/* $rcs]} {return 0} + log write 4 collar "Ignored $rcs, administrative archive" + return 1 + } + + proc UserPath {rcs iav} { + upvar 1 $iav isattic + + # Derive the user-visible path from the rcs path. Meaning: + # Chop off the ",v" suffix, and remove a possible "Attic". + + set f [string range $rcs 0 end-2] + + if {"Attic" eq [lindex [file split $rcs] end-1]} { + + # The construction below ensures that Attic/X maps to X + # instead of ./X. Otherwise, Y/Attic/X maps to Y/X. + + set fx [file dirname [file dirname $f]] + set f [file tail $f] + if {$fx ne "."} { set f [file join $fx $f] } + + set isattic 1 + } else { + set isattic 0 + } + + return $f + } + + proc IsSuperceded {base rcs usr isattic} { + ::variable myignore + + if {!$isattic} {return 0} + if {![file exists $base/$usr,v]} {return 0} + + # We have a regular archive and an Attic archive refering to + # the same user visible file. Ignore the file in the Attic. + # + # By default this is a problem causing an abort after the pass + # has completed. The user can however force us to ignore it. + # In that case the warning is still printed, but will not + # induce an abort any longer. + + if {$myignore} { + log write 2 collar "Ignored $rcs, superceded archive" + } else { + trouble warn "Ignored $rcs, superceded archive" + } + return 1 + } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::pass { + namespace export collar + namespace eval collar { + namespace import ::vc::fossil::import::cvs::repository + namespace import ::vc::fossil::import::cvs::state + namespace import ::vc::tools::trouble + namespace import ::vc::tools::log + log register collar + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::pass::collar 1.0 +return
Added tools/cvs2fossil/lib/c2f_pcollrev.tcl version [e9c8eea44f]
@@ -1,1 +1,644 @@ +## -*- 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 II. This pass parses the collected rcs archives and extracts +## all the information they contain (revisions, and symbols). + +# # ## ### ##### ######## ############# ##################### +## 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::pass ; # Pass management. +package require vc::fossil::import::cvs::repository ; # Repository management. +package require vc::fossil::import::cvs::state ; # State storage. +package require vc::fossil::import::cvs::integrity ; # State integrity checks. +package require vc::fossil::import::cvs::project::sym ; # Project level symbols. +package require vc::fossil::import::cvs::file::rev ; # File level revisions. +package require vc::rcs::parser ; # Rcs archive data extraction. + +# # ## ### ##### ######## ############# ##################### +## Register the pass with the management + +vc::fossil::import::cvs::pass define \ + CollectRev \ + {Collect revisions and symbols} \ + ::vc::fossil::import::cvs::pass::collrev + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::pass::collrev { + # # ## ### ##### ######## ############# + ## Public API + + typemethod setup {} { + # Define names and structure of the persistent state of this + # pass. + + state reading project + state reading file + + # We deal with per project and per file data, the first + # collated from the second. + + # Per file we have general information, ..., and then + # revisions and symbols. The latter can be further separated + # into tags and branches. At project level the per-file + # symbols information is merged. + + # File level ... + # Revisions, Branches, Tags + # + # Pseudo class hierarchy + # Tag <- Symbol <- Event + # Branch <- Symbol <- Event + # Revision <- Event + + state writing revision { + -- Revisions. Identified by a global numeric id each + -- belongs to a single file, identified by its id. It + -- further has a dotted revision number (DTN). + -- + -- Constraint: The dotted revision number is unique within + -- the file. See end of definition. + + rid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + fid INTEGER NOT NULL REFERENCES file, -- File owning revision. + rev TEXT NOT NULL, -- Dotted Rev Number. + + -- All revisions belong to a line-of-development, + -- identified by a symbol (project level). During data + -- collection it was a file-level branch symbol. + -- + -- Constraint: All the LOD symbols are in the same project + -- as the file itself. This cannot be + -- expressed in CREATE TABLE syntax. + + lod INTEGER NOT NULL REFERENCES symbol, -- Line of development + + -- The revisions in a file are organized in a forest of + -- trees, with the main lines defined through the parent / + -- child references. A revision without a parent is the + -- root of a tree, and a revision without a child is a + -- leaf. + + -- Constraints: All revisions coupled through parent/child + -- refer to the same LOD symbol. The parent + -- of a child of X is X. The child of a + -- parent of X is X. + + parent INTEGER REFERENCES revision, + child INTEGER REFERENCES revision, + + -- The representation of a branch in a tree is the + -- exception to the three constraints above. + + -- The beginning of a branch is represented by a non-NULL + -- bparent of a revision. This revision B is the first on + -- the branch. Its parent P is the revision the branch is + -- rooted in, and it is not the child of P. B and P refer + -- to different LOD symbols. The bparent of B is also its + -- LOD, and the LOD of its children. + + bparent INTEGER REFERENCES symbol, + + -- Lastly we keep information is about non-trunk default + -- branches (NTDB) in the revisions. + + -- All revisions on the NTDB have 'isdefault' TRUE, + -- everyone else FALSE. The last revision X on the NTDB + -- which is still considered to be on the trunk as well + -- has a non-NULL 'dbchild' which refers to the root of + -- the trunk. The root also has a non-NULL dbparent + -- refering to X. + + isdefault INTEGER NOT NULL, + dbparent INTEGER REFERENCES revision, + dbchild INTEGER REFERENCES revision, + + -- The main payload of the revision are the date/time it + -- was entered, its state, operation (= type/class), text + -- content, and meta data (author, log message, branch, + -- project). The last is encoded as single id, see table + -- 'meta'. The date/time is given in seconds since the + -- epoch, for easy comparison. The text content is an + -- (offset,length) pair into the rcs archive. + + op INTEGER NOT NULL REFERENCES optype, + date INTEGER NOT NULL, + state TEXT NOT NULL, + mid INTEGER NOT NULL REFERENCES meta, + coff INTEGER NOT NULL, + clen INTEGER NOT NULL, + + UNIQUE (fid, rev) -- The DTN is unique within the revision's file. + } + + state writing optype { + oid INTEGER NOT NULL PRIMARY KEY, + name TEXT NOT NULL, + UNIQUE(name) + } + state run { + INSERT INTO optype VALUES (-1,'delete'); -- The opcode names are the + INSERT INTO optype VALUES ( 0,'nothing'); -- fixed pieces, see myopstate + INSERT INTO optype VALUES ( 1,'add'); -- in file::rev. myopcode is + INSERT INTO optype VALUES ( 2,'change'); -- loaded from this. + } + + state writing revisionbranchchildren { + -- The non-primary children of a revision, as reachable + -- through a branch symbol, are listed here. This is + -- needed by pass 5 to break internal dependencies in a + -- changeset. + + rid INTEGER NOT NULL REFERENCES revision, + brid INTEGER NOT NULL REFERENCES revision, + UNIQUE(rid,brid) + } + + state writing tag { + tid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + fid INTEGER NOT NULL REFERENCES file, -- File the item belongs to + lod INTEGER REFERENCES symbol, -- Line of development (NULL => Trunk) + sid INTEGER NOT NULL REFERENCES symbol, -- Symbol capturing the tag + + rev INTEGER NOT NULL REFERENCES revision -- The revision being tagged. + } + + state writing branch { + bid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + fid INTEGER NOT NULL REFERENCES file, -- File the item belongs to + lod INTEGER REFERENCES symbol, -- Line of development (NULL => Trunk) + sid INTEGER NOT NULL REFERENCES symbol, -- Symbol capturing the branch + + root INTEGER NOT NULL REFERENCES revision, -- Revision the branch sprouts from + first INTEGER REFERENCES revision, -- First revision committed to the branch + bra TEXT NOT NULL, -- branch number + pos INTEGER NOT NULL -- creation order in root. + } + + # Project level ... + # pLineOfDevelopment, pSymbol, pBranch, pTag, pTrunk + # + # pTrunk <- pLineOfDevelopment + # pBranch <- pSymbol, pLineOfDevelopment + # pTag <- pSymbol, pLineOfDevelopment + + state writing symbol { + sid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + pid INTEGER NOT NULL REFERENCES project, -- Project the symbol belongs to + name TEXT NOT NULL, + type INTEGER NOT NULL REFERENCES symtype, -- enum { excluded = 0, tag, branch, undefined } + + tag_count INTEGER NOT NULL, -- How often the symbol is used as tag. + branch_count INTEGER NOT NULL, -- How often the symbol is used as branch + commit_count INTEGER NOT NULL, -- How often a file was committed on the symbol + + UNIQUE (pid, name) -- Symbols are unique within the project + } + + state writing blocker { + -- For each symbol we save which other symbols are + -- blocking its removal (if the user asks for it). + + sid INTEGER NOT NULL REFERENCES symbol, -- + bid INTEGER NOT NULL REFERENCES symbol, -- Sprouted from sid, blocks it. + UNIQUE (sid, bid) + } + + state writing parent { + -- For each symbol we save which other symbols can act as + -- a possible parent in some file, and how often. + + sid INTEGER NOT NULL REFERENCES symbol, -- + pid INTEGER NOT NULL REFERENCES symbol, -- Possible parent of sid + n INTEGER NOT NULL, -- How often pid can act as parent. + UNIQUE (sid, pid) + } + + state writing symtype { + tid INTEGER NOT NULL PRIMARY KEY, + name TEXT NOT NULL, + plural TEXT NOT NULL, + UNIQUE (name) + UNIQUE (plural) + } + state run { + INSERT INTO symtype VALUES (0,'excluded', 'excluded'); + INSERT INTO symtype VALUES (1,'tag', 'tags'); + INSERT INTO symtype VALUES (2,'branch', 'branches'); + INSERT INTO symtype VALUES (3,'undefined','undefined'); + } + + state writing meta { + -- Meta data of revisions. See revision.mid for the + -- reference. Many revisions can share meta data. This is + -- actually one of the criterions used to sort revisions + -- into changesets. + + mid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + + -- Meta data belongs to a specific project, stronger, to a + -- branch in that project. It further has a log message, + -- and its author. This is unique with the project and + -- branch. + + pid INTEGER NOT NULL REFERENCES project, -- + bid INTEGER NOT NULL REFERENCES symbol, -- + aid INTEGER NOT NULL REFERENCES author, -- + cid INTEGER NOT NULL REFERENCES cmessage, -- + + UNIQUE (pid, bid, aid, cid) + + -- Constraints: The project of the meta data of a revision + -- X is the same as the project of X itself. + -- + -- ............ The branch of the meta data of a revision + -- X is the same as the line of development + -- of X itself. + } + + # Authors and commit messages are fully global, i.e. per + # repository. + + state writing author { + aid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE + } + + state writing cmessage { + cid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + text TEXT NOT NULL UNIQUE + } + + project::sym getsymtypes + file::rev getopcodes + return + } + + typemethod load {} { + state reading symbol + state reading symtype + state reading optype + + project::sym getsymtypes + file::rev getopcodes + repository loadsymbols + return + } + + typemethod run {} { + # Pass manager interface. Executed to perform the + # functionality of the pass. + + set rbase [repository base?] + foreach project [repository projects] { + set base [file join $rbase [$project base]] + log write 1 collrev "Processing $base" + + foreach file [$project files] { + set path [$file path] + log write 2 collrev "Parsing $path" + if {[catch { + parser process [file join $base $path] $file + } msg]} { + global errorCode + if {$errorCode eq "vc::rcs::parser"} { + trouble fatal "$path is not a valid RCS archive ($msg)" + } else { + global errorInfo + trouble internal $errorInfo + } + } else { + # We persist the core of the data collected about + # each file immediately after it has been parsed + # and wrangled into shape, and then drop it from + # memory. This is done to keep the amount of + # required memory within sensible limits. Without + # doing it this way we would easily gobble up 1G + # of RAM or more with all the objects (revisions + # and file-level symbols). + + $file persist + } + + $file drop + } + + $project purgeghostsymbols + } + + repository persistrev + repository printrevstatistics + integrity strict + + log write 1 collrev "Scan 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 revision + state discard tag + state discard branch + state discard symbol + state discard blocker + state discard parent + state discard symtype + state discard meta + state discard author + state discard cmessage + return + } + + proc Paranoia {} { + # This code performs a number of paranoid checks of the + # database, searching for inconsistent cross-references. + log write 4 collrev {Check database consistency} + + set n 0 ; # Counter for the checks (we print an id before the + # main label). + + # Find all revisions which disagree with their line of + # development about the project they are owned by. + Check \ + {Revisions and their LODs have to be in the same project} \ + {disagrees with its LOD about owning project} { + SELECT F.name, R.rev + FROM revision R, file F, symbol S + WHERE R.fid = F.fid + AND R.lod = S.sid + AND F.pid != S.pid + ; + } + # Find all revisions which disgree with their meta data about + # the project they are owned by. + Check \ + {Revisions and their meta data have to be in the same project} \ + {disagrees with its meta data about owning project} { + SELECT F.name, R.rev + FROM revision R, file F, meta M + WHERE R.fid = F.fid + AND R.mid = M.mid + AND F.pid != M.pid + ; + } + # Find all revisions which disgree with their meta data about + # the branch/line of development they belong to. + Check \ + {Revisions and their meta data have to be in the same LOD} \ + {disagrees with its meta data about owning LOD} { + SELECT F.name, R.rev + FROM revision R, meta M, file F + WHERE R.mid = M.mid + AND R.lod != M.bid + AND R.fid = F.fid + ; + } + # Find all revisions with a primary child which disagrees + # about the file they belong to. + Check \ + {Revisions and their primary children have to be in the same file} \ + {disagrees with its primary child about the owning file} { + SELECT F.name, R.rev + FROM revision R, revision C, file F + WHERE R.fid = F.fid + AND R.child IS NOT NULL + AND R.child = C.rid + AND C.fid != R.fid + ; + } + + # Find all revisions with a branch parent symbol whose parent + # disagrees about the file they belong to. + Check \ + {Revisions and their branch children have to be in the same file} \ + {at the beginning of its branch and its parent disagree about the owning file} { + SELECT F.name, R.rev + FROM revision R, revision P, file F + WHERE R.fid = F.fid + AND R.bparent IS NOT NULL + AND R.parent = P.rid + AND R.fid != P.fid + ; + } + # Find all revisions with a non-NTDB child which disagrees + # about the file they belong to. + Check \ + {Revisions and their non-NTDB children have to be in the same file} \ + {disagrees with its non-NTDB child about the owning file} { + SELECT F.name, R.rev + FROM revision R, revision C, file F + WHERE R.fid = F.fid + AND R.dbchild IS NOT NULL + AND R.dbchild = C.rid + AND C.fid != R.fid + ; + } + # Find all revisions which have a primary child, but the child + # does not have them as parent. + Check \ + {Revisions have to be parents of their primary children} \ + {is not the parent of its primary child} { + SELECT F.name, R.rev + FROM revision R, revision C, file F + WHERE R.fid = F.fid + AND R.child IS NOT NULL + AND R.child = C.rid + AND C.parent != R.rid + ; + } + # Find all revisions which have a primrary child, but the + # child has a branch parent symbol making them brach starters. + Check \ + {Primary children of revisions must not start branches} \ + {is parent of a primary child which is the beginning of a branch} { + SELECT F.name, R.rev + FROM revision R, revision C, file F + WHERE R.fid = F.fid + AND R.child IS NOT NULL + AND R.child = C.rid + AND C.bparent IS NOT NULL + ; + } + # Find all revisions without branch parent symbol which have a + # parent, but the parent does not have them as primary child. + Check \ + {Revisions have to be primary children of their parents, if any} \ + {is not the child of its parent} { + SELECT F.name, R.rev + FROM revision R, revision P, file F + WHERE R.fid = F.fid + AND R.bparent IS NULL + AND R.parent IS NOT NULL + AND R.parent = P.rid + AND P.child != R.rid + ; + } + # Find all revisions with a branch parent symbol which do not + # have a parent. + Check \ + {Branch starting revisions have to have a parent} \ + {at the beginning of its branch has no parent} { + SELECT F.name, R.rev + FROM revision R, file F + WHERE R.fid = F.fid + AND R.bparent IS NOT NULL + AND R.parent IS NULL + ; + } + # Find all revisions with a branch parent symbol whose parent + # has them as primary child. + Check \ + {Branch starting revisions must not be primary children of their parents} \ + {at the beginning of its branch is the primary child of its parent} { + SELECT F.name, R.rev + FROM revision R, revision P, file F + WHERE R.fid = F.fid + AND R.bparent IS NOT NULL + AND R.parent IS NOT NULL + AND R.parent = P.rid + AND P.child = R.rid + ; + } + # Find all revisions with a non-NTDB child which are not on + # the NTDB. + Check \ + {NTDB to trunk transition has to begin on NTDB} \ + {has a non-NTDB child, yet is not on the NTDB} { + SELECT F.name, R.rev + FROM revision R, file F + WHERE R.fid = F.fid + AND R.dbchild IS NOT NULL + AND NOT R.isdefault + ; + } + # Find all revisions with a NTDB parent which are on the NTDB. + Check \ + {NTDB to trunk transition has to end on non-NTDB} \ + {has a NTDB parent, yet is on the NTDB} { + SELECT F.name, R.rev + FROM revision R, file F + WHERE R.fid = F.fid + AND R.dbparent IS NOT NULL + AND R.isdefault + ; + } + # Find all revisions with a child which disagrees about the + # line of development they belong to. + Check \ + {Revisions and their primary children have to be in the same LOD} \ + {and its primary child disagree about their LOD} { + SELECT F.name, R.rev + FROM revision R, revision C, file F + WHERE R.fid = F.fid + AND R.child IS NOT NULL + AND R.child = C.rid + AND C.lod != R.lod + ; + } + # Find all revisions with a non-NTDB child which agrees about + # the line of development they belong to. + Check \ + {NTDB and trunk revisions have to be in different LODs} \ + {on NTDB and its non-NTDB child wrongly agree about their LOD} { + SELECT F.name, R.rev + FROM revision R, revision C, file F + WHERE R.fid = F.fid + AND R.dbchild IS NOT NULL + AND R.dbchild = C.rid + AND C.lod = R.lod + ; + } + # Find all revisions with a branch parent symbol which is not + # their LOD. + Check \ + {Branch starting revisions have to have their LOD as branch parent symbol} \ + {at the beginning of its branch does not have the branch symbol as its LOD} { + SELECT F.name, R.rev + FROM revision R, file F + WHERE R.fid = F.fid + AND R.bparent IS NOT NULL + AND R.lod != R.bparent + ; + } + # Find all revisions with a branch parent symbol whose parent + # is in the same line of development. + Check \ + {Revisions and their branch children have to be in different LODs} \ + {at the beginning of its branch and its parent wrongly agree about their LOD} { + SELECT F.name, R.rev + FROM revision R, revision P, file F + WHERE R.fid = F.fid + AND R.bparent IS NOT NULL + AND R.parent = P.rid + AND R.lod = P.lod + ; + } + return + } + + proc Check {header label sql} { + upvar 1 n n + set ok 1 + foreach {fname revnr} [state run $sql] { + set ok 0 + trouble fatal "$fname <$revnr> $label" + } + log write 5 collrev "\[[format %02d [incr n]]\] [expr {$ok ? "Ok " : "Failed"}] ... $header" + return + } + + # # ## ### ##### ######## ############# + ## Internal methods + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::pass { + namespace export collrev + namespace eval collrev { + namespace import ::vc::rcs::parser + namespace import ::vc::fossil::import::cvs::repository + namespace import ::vc::fossil::import::cvs::state + namespace import ::vc::fossil::import::cvs::integrity + namespace eval project { + namespace import ::vc::fossil::import::cvs::project::sym + } + namespace eval file { + namespace import ::vc::fossil::import::cvs::file::rev + } + namespace import ::vc::tools::trouble + namespace import ::vc::tools::log + log register collrev + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::pass::collrev 1.0 +return
Added tools/cvs2fossil/lib/c2f_pcollsym.tcl version [7553c6538a]
@@ -1,1 +1,303 @@ +## -*- 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 reading symbol + state reading blocker + state reading parent + + state writing 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 + } + 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 + + proc UnconvertedSymbols {} { + # Paranoia - Have we left symbols without conversion + # information (i.e. with type 'undefined') ? + + set undef [project::sym undef] + + foreach {pname sname} [state run { + SELECT P.name, S.name + FROM project P, symbol S + WHERE P.pid = S.pid + AND S.type = $undef + }] { + 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)) ? + + foreach {pname sname} [state run { + SELECT P.name, S.name + FROM project P, symbol S + WHERE P.pid = S.pid + AND S.type NOT IN (0,1,2) + }] { + 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] + + foreach {pname sname bname} [state run { + SELECT P.name, S.name, SB.name + FROM project P, symbol S, blocker B, symbol SB + WHERE P.pid = S.pid + AND S.type = $excl + AND S.sid = B.sid + AND B.bid = SB.sid + AND SB.type != $excl + }] { + 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] + + foreach {pname sname} [state run { + SELECT P.name, S.name + FROM project P, symbol S + WHERE P.pid = S.pid + AND S.type = $tag + AND S.commit_count > 0 + }] { + 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); + DELETE FROM parent + WHERE pid IN (SELECT sid + FROM symbol + WhERE type = $excl); + } + 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 symbol, we + # do not care about their prefered parents and do not + # attempt to compute them. + + foreach {s p sname pname prname} [state run { + SELECT S.sid, P.pid, S.name, SB.name, PR.name + FROM symbol S, parent P, symbol SB, project PR + WHERE S.sid = P.sid + AND P.pid = SB.sid + AND S.pid = PR.pid + AND S.type != $excl + ORDER BY P.n ASC, P.pid DESC + -- 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. + }] { + set prefered($s) [list $p $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. + + foreach {pname sname} [state run { + SELECT PR.name, S.name + FROM project PR, symbol S LEFT OUTER JOIN preferedparent P + ON S.sid = P.sid + WHERE P.pid IS NULL + AND S.name != ':trunk:' + AND S.pid = PR.pid + AND S.type != $excl + }] { + 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
Added tools/cvs2fossil/lib/c2f_pfiltersym.tcl version [29f48baf16]
@@ -1,1 +1,522 @@ +## -*- 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 IV. Coming after the symbol collation pass this pass now +## removes all revisions and symbols referencing any of the excluded +## symbols from the persistent database. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require vc::tools::misc ; # Text formatting. +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::integrity ; # State storage integrity checks. +package require vc::fossil::import::cvs::project::sym ; # Project level symbols + +# # ## ### ##### ######## ############# ##################### +## Register the pass with the management + +vc::fossil::import::cvs::pass define \ + FilterSymbols \ + {Filter symbols, remove all excluded pieces} \ + ::vc::fossil::import::cvs::pass::filtersym + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::pass::filtersym { + # # ## ### ##### ######## ############# + ## Public API + + typemethod setup {} { + # Define names and structure of the persistent state of this + # pass. + + state reading symbol + state reading blocker + state reading parent + state reading preferedparent + state reading revision + state reading revisionbranchchildren + state reading branch + state reading tag + + state writing noop { + id INTEGER NOT NULL PRIMARY KEY, -- tag/branch reference + noop INTEGER NOT NULL + } + 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. + + # The removal of excluded symbols and everything referencing + # to them is done completely in the database. + + state transaction { + FilterExcludedSymbols + MutateSymbols + AdjustParents + RefineSymbols + + repository printrevstatistics + + # Strict integrity enforces that all meta entries are in + # the same LOD as the revision using them. At this point + # this may not be true any longer. If a NTDB was excluded + # then all revisions it shared with the trunk were moved + # to the trunk LOD, however their meta entries will still + # refer to the now gone LOD symbol. This is fine however, + # it will not affect our ability to use the meta entries + # to distinguish and group revisions into changesets. It + # should be noted that we cannot simply switch the meta + # entries over to the trunk either, as that may cause the + # modified entries to violate the unique-ness constrain + # set on that table. + integrity metarelaxed + } + + log write 1 filtersym "Filtering 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. + return + } + + # # ## ### ##### ######## ############# + ## Internal methods + + proc FilterExcludedSymbols {} { + log write 3 filtersym "Remove the excluded symbols and their users" + + # We pull all the excluded symbols together into a table for + # easy reference by the upcoming DELETE and other statements. + # ('x IN table' clauses). + + set excl [project::sym excluded] + + state run { + CREATE TEMPORARY TABLE excludedsymbols AS + SELECT sid + FROM symbol + WHERE type = $excl + } + + # First we have to handle the possibility of an excluded + # NTDB. This is a special special case there we have to + # regraft the revisions which are shared between the NTDB and + # Trunk onto the trunk, preventing their deletion later. We + # have code for that in 'file', however that operated on the + # in-memory revision objects, which we do not have here. We do + # the same now without object, by directly manipulating the + # links in the database. + + array set ntdb {} + array set link {} + + foreach {id parent transfer} [state run { + SELECT R.rid, R.parent, R.dbchild + FROM revision R, symbol S + WHERE R.lod = S.sid + AND S.sid IN excludedsymbols + AND R.isdefault + }] { + set ntdb($id) $parent + if {$transfer eq ""} continue + set link($id) $transfer + } + + foreach joint [array names link] { + # The joints are the highest NTDB revisions which are + # shared with their respective trunk. We disconnect from + # their NTDB children, and make them parents of their + # 'dbchild'. The associated 'dbparent' is squashed + # instead. All parents of the joints are moved to the + # trunk as well. + + set tjoint $link($joint) + set tlod [state one { + SELECT lod FROM revision WHERE rid = $tjoint + }] + + # Covnert db/parent/child into regular parent/child links. + state run { + UPDATE revision SET dbparent = NULL, parent = $joint WHERE rid = $tjoint ; + UPDATE revision SET dbchild = NULL, child = $tjoint WHERE rid = $joint ; + } + while {1} { + # Move the NTDB trunk revisions to trunk. + state run { + UPDATE revision SET lod = $tlod, isdefault = 0 WHERE rid = $joint + } + set last $joint + set joint $ntdb($joint) + if {![info exists ntdb($joint)]} break + } + + # Reached the NTDB basis in the trunk. Finalize the + # parent/child linkage and squash the branch parent symbol + # reference. + + state run { + UPDATE revision SET child = $last WHERE rid = $joint ; + UPDATE revision SET bparent = NULL WHERE rid = $last ; + } + } + + # Now that the special case is done we can simply kill all the + # revisions, tags, and branches referencing any of the + # excluded symbols in some way. This is easy as we do not have + # to select them again and again from the base tables any + # longer. + + state run { + CREATE TEMPORARY TABLE excludedrevisions AS + SELECT rid FROM revision WHERE lod IN excludedsymbols; + + DELETE FROM revision WHERE lod IN excludedsymbols; + DELETE FROM tag WHERE lod IN excludedsymbols; + DELETE FROM tag WHERE sid IN excludedsymbols; + DELETE FROM branch WHERE lod IN excludedsymbols; + DELETE FROM branch WHERE sid IN excludedsymbols; + + DELETE FROM revisionbranchchildren WHERE rid IN excludedrevisions; + DELETE FROM revisionbranchchildren WHERE brid IN excludedrevisions; + + DROP TABLE excludedrevisions; + DROP TABLE excludedsymbols; + } + return + } + + proc MutateSymbols {} { + # Next, now that we know which symbols are what we look for + # file level tags which are actually converted as branches + # (project level, and vice versa), and move them to the + # correct tables. + + # # ## ### ##### ######## ############# + + log write 3 filtersym "Mutate symbols, preparation" + + set branch [project::sym branch] + set tag [project::sym tag] + + set tagstomutate [state run { + SELECT T.tid, T.fid, T.lod, T.sid, T.rev + FROM tag T, symbol S + WHERE T.sid = S.sid + AND S.type = $branch + }] + + set branchestomutate [state run { + SELECT B.bid, B.fid, B.lod, B.sid, B.root, B.first, B.bra + FROM branch B, symbol S + WHERE B.sid = S.sid + AND S.type = $tag + }] + + log write 4 filtersym "Changing [nsp [expr {[llength $tagstomutate]/5}] tag] into branches" + log write 4 filtersym "Changing [nsp [expr {[llength $branchestomutate]/7}] branch branches] into tags" + + # # ## ### ##### ######## ############# + + log write 3 filtersym "Mutate tags to branches" + + foreach {id fid lod sid rev} $tagstomutate { + state run { + DELETE FROM tag WHERE tid = $id ; + INSERT INTO branch (bid, fid, lod, sid, root, first, bra, pos) + VALUES ($id, $fid, $lod, $sid, $rev, NULL, '', -1); + } + } + + log write 3 filtersym "Ok." + + # # ## ### ##### ######## ############# + + log write 3 filtersym "Mutate branches to tags" + + foreach {id fid lod sid root first bra} $branchestomutate { + state run { + DELETE FROM branch WHERE bid = $id ; + INSERT INTO tag (tid, fid, lod, sid, rev) + VALUES ($id, $fid, $lod, $sid, $root); + } + } + + log write 3 filtersym "Ok." + + # # ## ### ##### ######## ############# + return + } + + # Adjust the parents of symbols to their preferred parents. + + # If a file level ymbol has a preferred parent that is different + # than its current parent, and if the preferred parent is an + # allowed parent of the symbol in this file, then we graft the + # aSymbol onto its preferred parent. + + proc AdjustParents {} { + log write 3 filtersym "Adjust parents, loading data in preparation" + + # We pull important maps once into memory so that we do quick + # hash lookup later when processing the graft candidates. + + # Tag/Branch names ... + array set sn [state run { SELECT T.tid, S.name FROM tag T, symbol S WHERE T.sid = S.sid }] + array set sn [state run { SELECT B.bid, S.name FROM branch B, symbol S WHERE B.sid = S.sid }] + # Symbol names ... + array set sx [state run { SELECT L.sid, L.name FROM symbol L }] + # Files and projects. + array set fpn {} + foreach {id fn pn} [state run { + SELECT F.fid, F.name, P.name + FROM file F, project P + WHERE F.pid = P.pid + }] { set fpn($id) [list $fn $pn] } + + set tagstoadjust [state run { + SELECT T.tid, T.fid, T.lod, P.pid, S.name, R.rev, R.rid + FROM tag T, preferedparent P, symbol S, revision R + WHERE T.sid = P.sid + AND T.lod != P.pid + AND P.pid = S.sid + AND S.name != ':trunk:' + AND T.rev = R.rid + }] + + set branchestoadjust [state run { + SELECT B.bid, B.fid, B.lod, B.pos, P.pid, S.name, R.rev, R.rid + FROM branch B, preferedparent P, symbol S, revision R + WHERE B.sid = P.sid + AND B.lod != P.pid + AND P.pid = S.sid + AND S.name != ':trunk:' + AND B.root = R.rid + }] + + set tmax [expr {[llength $tagstoadjust] / 7}] + set bmax [expr {[llength $branchestoadjust] / 8}] + + log write 4 filtersym "Reparenting at most [nsp $tmax tag]" + log write 4 filtersym "Reparenting at most [nsp $bmax branch branches]" + + log write 3 filtersym "Adjust tag parents" + + # Find the tags whose current parent (lod) is not the prefered + # parent, the prefered parent is not the trunk, and the + # prefered parent is a possible parent per the tag's revision. + + set fmt %[string length $tmax]s + set mxs [format $fmt $tmax] + + set n 0 + foreach {id fid lod pid preferedname revnr rid} $tagstoadjust { + + # BOTTLE-NECK ... + # + # The check if the candidate (pid) is truly viable is + # based finding the branch as possible parent, and done + # now instead of as part of the already complex join. + # + # ... AND P.pid IN (SELECT B.sid + # FROM branch B + # WHERE B.root = R.rid) + + if {![state one { + SELECT COUNT(*) + FROM branch B + WHERE B.sid = $pid + AND B.root = $rid + }]} { + incr tmax -1 + set mxs [format $fmt $tmax] + continue + } + + # + # BOTTLE-NECK ... + + # The names for use in the log output are retrieved + # separately, to keep the join selecting the adjustable + # tags small, not burdened with the dereferencing of links + # to name. + + set tagname $sn($id) + set oldname $sx($lod) + struct::list assign $fpn($fid) fname prname + + # Do the grafting. + + log write 4 filtersym "\[[format $fmt $n]/$mxs\] $prname : Grafting tag '$tagname' on $fname/$revnr from '$oldname' onto '$preferedname'" + state run { UPDATE tag SET lod = $pid WHERE tid = $id ; } + incr n + } + + log write 3 filtersym "Reparented [nsp $n tag]" + + log write 3 filtersym "Adjust branch parents" + + # Find the branches whose current parent (lod) is not the + # prefered parent, the prefered parent is not the trunk, and + # the prefered parent is a possible parent per the branch's + # revision. + + set fmt %[string length $bmax]s + set mxs [format $fmt $bmax] + + set n 0 + foreach {id fid lod pos pid preferedname revnr rid} $branchestoadjust { + + # BOTTLE-NECK ... + # + # The check if the candidate (pid) is truly viable is + # based on the branch positions in the spawning revision, + # and done now instead of as part of the already complex + # join. + # + # ... AND P.pid IN (SELECT BX.sid + # FROM branch BX + # WHERE BX.root = R.rid + # AND BX.pos > B.pos) + + if {![state one { + SELECT COUNT(*) + FROM branch B + WHERE B.sid = $pid + AND B.root = $rid + AND B.pos > $pos + }]} { + incr bmax -1 + set mxs [format $fmt $bmax] + continue + } + + # + # BOTTLE-NECK ... + + # The names for use in the log output are retrieved + # separately, to keep the join selecting the adjustable + # tags small, not burdened with the dereferencing of links + # to name. + + set braname $sn($id) + set oldname $sx($lod) + struct::list assign $fpn($fid) fname prname + + # Do the grafting. + + log write 4 filtersym "\[[format $fmt $n]/$mxs\] $prname : Grafting branch '$braname' on $fname/$revnr from '$oldname' onto '$preferedname'" + state run { UPDATE tag SET lod = $pid WHERE tid = $id ; } + incr n + } + + log write 3 filtersym "Reparented [nsp $n branch branches]" + return + } + + proc RefineSymbols {} { + # Tags and branches are marked as normal/noop based on the op + # of their revision. + + log write 3 filtersym "Refine symbols (no-op or not?)" + + log write 4 filtersym " Regular tags" + state run { + INSERT INTO noop + SELECT T.tid, 0 + FROM tag T, revision R + WHERE T.rev = R.rid + AND R.op != 0 -- 0 == nothing + } + + log write 4 filtersym " No-op tags" + state run { + INSERT INTO noop + SELECT T.tid, 1 + FROM tag T, revision R + WHERE T.rev = R.rid + AND R.op = 0 -- nothing + } + + log write 4 filtersym " Regular branches" + state run { + INSERT INTO noop + SELECT B.bid, 0 + FROM branch B, revision R + WHERE B.root = R.rid + AND R.op != 0 -- nothing + } + + log write 4 filtersym " No-op branches" + state run { + INSERT INTO noop + SELECT B.bid, 1 + FROM branch B, revision R + WHERE B.root = R.rid + AND R.op = 0 -- nothing + } + return + } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::pass { + namespace export filtersym + namespace eval filtersym { + namespace import ::vc::fossil::import::cvs::repository + namespace import ::vc::fossil::import::cvs::state + namespace import ::vc::fossil::import::cvs::integrity + namespace eval project { + namespace import ::vc::fossil::import::cvs::project::sym + } + namespace import ::vc::tools::misc::nsp + namespace import ::vc::tools::log + log register filtersym + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::pass::filtersym 1.0 +return
Added tools/cvs2fossil/lib/c2f_pinitcsets.tcl version [10710518c2]
@@ -1,1 +1,352 @@ +## -*- 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 V. This pass creates the initial set of project level +## revisions, aka changesets. Later passes will refine them, puts them +## into proper order, set their dependencies, etc. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require vc::tools::misc ; # Text formatting. +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 +package require vc::fossil::import::cvs::project::rev ; # Project level changesets + +# # ## ### ##### ######## ############# ##################### +## Register the pass with the management + +vc::fossil::import::cvs::pass define \ + InitCsets \ + {Initialize ChangeSets} \ + ::vc::fossil::import::cvs::pass::initcsets + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::pass::initcsets { + # # ## ### ##### ######## ############# + ## Public API + + typemethod setup {} { + # Define the names and structure of the persistent state of + # this pass. + + state reading meta + state reading revision + state reading revisionbranchchildren + state reading branch + state reading tag + state reading symbol + + # Data per changeset, namely the project it belongs to, how it + # was induced (revision or symbol), plus reference to the + # primary entry causing it (meta entry or symbol). An adjunct + # table translates the type id's into human readable labels. + + state writing changeset { + cid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + pid INTEGER NOT NULL REFERENCES project, + type INTEGER NOT NULL REFERENCES cstype, + src INTEGER NOT NULL -- REFERENCES meta|symbol (type dependent) + } + state writing cstype { + tid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + UNIQUE (name) + } + state run { + INSERT INTO cstype VALUES (0,'rev'); + INSERT INTO cstype VALUES (1,'sym'); + } + + # Map from changesets to the (file level) revisions they + # contain. The pos'ition provides an order of the revisions + # within a changeset. They are unique within the changeset. + # The revisions are in principle unique, if we were looking + # only at revision changesets. However a revision can appear + # in both revision and symbol changesets, and in multiple + # symbol changesets as well. So we can only say that it is + # unique within the changeset. + # + # TODO: Check if integrity checks are possible. + + state writing csrevision { + cid INTEGER NOT NULL REFERENCES changeset, + pos INTEGER NOT NULL, + rid INTEGER NOT NULL REFERENCES revision, + UNIQUE (cid, pos), + UNIQUE (cid, rid) + } + + project::rev getcstypes + return + } + + typemethod load {} { + # Pass manager interface. Executed to load data computed by + # this pass into memory when this pass is skipped instead of + # executed. + + state reading changeset + state reading csrevision + state reading cstype + + foreach {id pid cstype srcid} [state run { + SELECT C.cid, C.pid, CS.name, C.src + FROM changeset C, cstype CS + WHERE C.type = CS.tid + ORDER BY C.cid + }] { + set r [project::rev %AUTO% [repository projectof $pid] $cstype $srcid [state run { + SELECT C.rid + FROM csrevision C + WHERE C.cid = $id + ORDER BY C.pos + }]] + $r setid $id + } + + project::rev getcstypes + return + } + + typemethod run {} { + # Pass manager interface. Executed to perform the + # functionality of the pass. + + state transaction { + CreateRevisionChangesets ; # Group file revisions into csets. + BreakInternalDependencies ; # Split the csets based on internal conflicts. + CreateSymbolChangesets ; # Create csets for tags and branches. + PersistTheChangesets + + repository printcsetstatistics + } + 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 changeset + state discard cstype + state discard csrevision + return + } + + # # ## ### ##### ######## ############# + ## Internal methods + + proc CreateRevisionChangesets {} { + log write 3 initcsets {Create changesets based on revisions} + + # To get the initial of changesets we first group all file + # level revisions using the same meta data entry together. As + # the meta data encodes not only author and log message, but + # also line of development and project we can be sure that + # revisions in different project and lines of development are + # not grouped together. In contrast to cvs2svn we do __not__ + # use distance in time between revisions to break them + # apart. We have seen CVS repositories (from SF) where a + # single commit contained revisions several hours apart, + # likely due to trouble on the server hosting the repository. + + # We order the revisions here by time, this will help the + # later passes (avoids joins later to get at the ordering + # info). + + set n 0 + + set lastmeta {} + set lastproject {} + set revisions {} + + # Note: We could have written this loop to create the csets + # early, extending them with all their revisions. This + # however would mean lots of (slow) method invokations + # on the csets. Doing it like this, late creation, means + # less such calls. None, but the creation itself. + + foreach {mid rid pid} [state run { + SELECT M.mid, R.rid, M.pid + FROM revision R, meta M -- R ==> M, using PK index of M. + WHERE R.mid = M.mid + ORDER BY M.mid, R.date + }] { + if {$lastmeta != $mid} { + if {[llength $revisions]} { + incr n + set p [repository projectof $lastproject] + project::rev %AUTO% $p rev $lastmeta $revisions + set revisions {} + } + set lastmeta $mid + set lastproject $pid + } + lappend revisions $rid + } + + if {[llength $revisions]} { + incr n + set p [repository projectof $lastproject] + project::rev %AUTO% $p rev $lastmeta $revisions + } + + log write 4 initcsets "Created [nsp $n {revision changeset}]" + return + } + + proc CreateSymbolChangesets {} { + log write 3 initcsets {Create changesets based on symbols} + + # Tags and branches induce changesets as well, containing the + # revisions they are attached to (tags), or spawned from + # (branches). + + set n 0 + + # First process the tags, then the branches. We know that + # their ids do not overlap with each other. + + set lastsymbol {} + set lastproject {} + set revisions {} + + foreach {sid rid pid} [state run { + SELECT S.sid, R.rid, S.pid + FROM tag T, revision R, symbol S -- T ==> R/S, using PK indices of R, S. + WHERE T.rev = R.rid + AND T.sid = S.sid + ORDER BY S.sid, R.date + }] { + if {$lastsymbol != $sid} { + if {[llength $revisions]} { + incr n + set p [repository projectof $lastproject] + project::rev %AUTO% $p sym $lastsymbol $revisions + set revisions {} + } + set lastsymbol $sid + set lastproject $pid + } + lappend revisions $rid + } + + if {[llength $revisions]} { + incr n + set p [repository projectof $lastproject] + project::rev %AUTO% $p sym $lastsymbol $revisions + } + + set lastsymbol {} + set lasproject {} + set revisions {} + + foreach {sid rid pid} [state run { + SELECT S.sid, R.rid, S.pid + FROM branch B, revision R, symbol S -- B ==> R/S, using PK indices of R, S. + WHERE B.root = R.rid + AND B.sid = S.sid + ORDER BY S.sid, R.date + }] { + if {$lastsymbol != $sid} { + if {[llength $revisions]} { + incr n + set p [repository projectof $lastproject] + project::rev %AUTO% $p sym $lastsymbol $revisions + set revisions {} + } + set lastsymbol $sid + set lastproject $pid + } + lappend revisions $rid + } + + if {[llength $revisions]} { + incr n + set p [repository projectof $lastproject] + project::rev %AUTO% $p sym $lastsymbol $revisions + } + + log write 4 initcsets "Created [nsp $n {symbol changeset}]" + return + } + + proc BreakInternalDependencies {} { + # This code operates on the revision changesets created by + # 'CreateRevisionChangesets'. As such it has to follow after + # it, before the symbol changesets are made. The changesets + # are inspected for internal conflicts and any such are broken + # by splitting the problematic changeset into multiple + # fragments. The results are changesets which have no internal + # dependencies, only external ones. + + log write 3 initcsets {Break internal dependencies} + set old [llength [project::rev all]] + + foreach cset [project::rev all] { + $cset breakinternaldependencies + } + + set n [expr {[llength [project::rev all]] - $old}] + log write 4 initcsets "Created [nsp $n {additional revision changeset}]" + log write 4 initcsets Ok. + return + } + + proc PersistTheChangesets {} { + log write 3 initcsets "Saving [nsp [llength [project::rev all]] {initial changeset}] to the persistent state" + + foreach cset [project::rev all] { + $cset persist + } + + log write 4 initcsets Ok. + return + } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::pass { + namespace export initcsets + namespace eval initcsets { + namespace import ::vc::fossil::import::cvs::repository + namespace import ::vc::fossil::import::cvs::state + namespace eval project { + namespace import ::vc::fossil::import::cvs::project::rev + } + namespace import ::vc::tools::misc::* + namespace import ::vc::tools::log + log register initcsets + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::pass::initcsets 1.0 +return
Added tools/cvs2fossil/lib/c2f_plodmgr.tcl version [cb6fc6ef5f]
@@ -1,1 +1,57 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## Lines of Development in a project (Symbols, and the trunk). + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::project::lodmgr { + # # ## ### ##### ######## ############# + ## Public API + + constructor {} { + return + } + + # # ## ### ##### ######## ############# + ## State + + # # ## ### ##### ######## ############# + ## Internal methods + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hastypeinfo no ; # no type introspection + pragma -hasinfo no ; # no object introspection + pragma -hastypemethods no ; # type is not relevant. + pragma -simpledispatch yes ; # simple fast dispatch + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::project { + namespace export lodmgr +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::project::lodmgr 1.0 +return
Added tools/cvs2fossil/lib/c2f_prev.tcl version [458c8956e4]
@@ -1,1 +1,601 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## Revisions per project, aka Changesets. These objects are first used +## in pass 5, which creates the initial set covering the repository. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require vc::tools::misc ; # Text formatting +package require vc::tools::trouble ; # Error reporting. +package require vc::tools::log ; # User feedback. +package require vc::fossil::import::cvs::state ; # State storage. + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::project::rev { + # # ## ### ##### ######## ############# + ## Public API + + constructor {project cstype srcid revisions} { + set myid [incr mycounter] + set myproject $project + set mytype $cstype + set mysrcid $srcid + set myrevisions $revisions + + # Keep track of the generated changesets and of the inverse + # mapping from revisions to them. + lappend mychangesets $self + foreach r $revisions { set myrevmap($r) $self } + return + } + + method id {} { return $myid } + method revisions {} { return $myrevisions } + method data {} { return [list $myproject $mytype $mysrcid] } + + method setid {id} { set myid $id ; return } + + method bysymbol {} { return [expr {$mytype eq "sym"}] } + method byrevision {} { return [expr {$mytype eq "rev"}] } + + method successors {} { + # NOTE / FUTURE: Possible bottleneck. + set csets {} + foreach {_ children} [$self nextmap] { + foreach child $children { + lappend csets $myrevmap($child) + } + } + return [lsort -unique $csets] + } + + method nextmap {} { + if {[llength $mynextmap]} { return $mynextmap } + PullSuccessorRevisions tmp $myrevisions + set mynextmap [array get tmp] + return $mynextmap + } + + method breakinternaldependencies {} { + # This method inspects the changesets for internal + # dependencies. Nothing is done if there are no + # such. Otherwise the changeset is split into a set of + # fragments without internal dependencies, transforming the + # internal dependencies into external ones. The new changesets + # are added to the list of all changesets. + + # We perform all necessary splits in one go, instead of only + # one. The previous algorithm, adapted from cvs2svn, computed + # a lot of state which was thrown away and then computed again + # for each of the fragments. It should be easier to update and + # reuse that state. + + # The code checks only sucessor dependencies, as this + # automatically covers the predecessor dependencies as well (A + # successor dependency a -> b is also a predecessor dependency + # b -> a). + + # Array of dependencies (parent -> child). This is pulled from + # the state, and limited to successors within the changeset. + + array set dependencies {} + PullInternalSuccessorRevisions dependencies $myrevisions + if {![array size dependencies]} {return 0} ; # Nothing to break. + + log write 6 csets ...<$myid>....................................................... + + # We have internal dependencies to break. We now iterate over + # all positions in the list (which is chronological, at least + # as far as the timestamps are correct and unique) and + # determine the best position for the break, by trying to + # break as many dependencies as possible in one go. When a + # break was found this is redone for the fragments coming and + # after, after upding the crossing information. + + # Data structures: + # Map: POS revision id -> position in list. + # CROSS position in list -> number of dependencies crossing it + # DEPC dependency -> positions it crosses + # List: RANGE Of the positions itself. + # A dependency is a single-element map parent -> child + + InitializeBreakState $myrevisions + + set fragments {} + set pending [list $range] + set at 0 + array set breaks {} + + while {$at < [llength $pending]} { + set current [lindex $pending $at] + + log write 6 csets ". . .. ... ..... ........ ............." + log write 6 csets "Scheduled [join [PRs [lrange $pending $at end]] { }]" + log write 6 csets "Considering [PR $current] \[$at/[llength $pending]\]" + + set best [FindBestBreak $current] + + if {$best < 0} { + # The inspected range has no internal + # dependencies. This is a complete fragment. + lappend fragments $current + + log write 6 csets "No breaks, final" + } else { + # Split the range and schedule the resulting fragments + # for further inspection. Remember the number of + # dependencies cut before we remove them from + # consideration, for documentation later. + + set breaks($best) $cross($best) + + log write 6 csets "Best break @ $best, cutting [nsp $cross($best) dependency dependencies]" + + # Note: The value of best is an abolute location in + # myrevisions. Use the start of current to make it an + # index absolute to current. + + set brel [expr {$best - [lindex $current 0]}] + set bnext $brel ; incr bnext + set fragbefore [lrange $current 0 $brel] + set fragafter [lrange $current $bnext end] + + log write 6 csets "New pieces [PR $fragbefore] [PR $fragafter]" + + if {![llength $fragbefore]} { + trouble internal "Tried to split off a zero-length fragment at the beginning" + } + if {![llength $fragafter]} { + trouble internal "Tried to split off a zero-length fragment at the end" + } + + lappend pending $fragbefore $fragafter + CutAt $best + } + + incr at + } + + log write 6 csets ". . .. ... ..... ........ ............." + + # Create changesets for the fragments, reusing the current one + # for the first fragment. We sort them in order to allow + # checking for gaps and nice messages. + + set fragments [lsort -index 0 -integer $fragments] + + #puts \t.[join [PRs $fragments] .\n\t.]. + + Border [lindex $fragments 0] firsts firste + + if {$firsts != 0} { + trouble internal "Bad fragment start @ $firsts, gap, or before beginning of the range" + } + + set laste $firste + foreach fragment [lrange $fragments 1 end] { + Border $fragment s e + if {$laste != ($s - 1)} { + trouble internal "Bad fragment border <$laste | $s>, gap or overlap" + } + + set new [$type %AUTO% $myproject $mytype $mysrcid [lrange $myrevisions $s $e]] + + log write 4 csets "Breaking <$myid> @ $laste, new <[$new id]>, cutting $breaks($laste)" + + set laste $e + } + + if {$laste != ([llength $myrevisions]-1)} { + trouble internal "Bad fragment end @ $laste, gap, or beyond end of the range" + } + + # Put the first fragment into the current changeset. + set myrevisions [lrange $myrevisions 0 $firste] + + return 1 + } + + method persist {} { + set tid $mycstype($mytype) + set pid [$myproject id] + set pos 0 + + state transaction { + state run { + INSERT INTO changeset (cid, pid, type, src) + VALUES ($myid, $pid, $tid, $mysrcid); + } + + foreach rid $myrevisions { + state run { + INSERT INTO csrevision (cid, pos, rid) + VALUES ($myid, $pos, $rid); + } + incr pos + } + } + return + } + + method timerange {} { + set theset ('[join $myrevisions {','}]') + return [state run " + SELECT MIN(R.date), MAX(R.date) + FROM revision R + WHERE R.rid IN $theset + "] + } + + method drop {} { + state transaction { + state run { + DELETE FROM changeset WHERE cid = $myid; + DELETE FROM csrevision WHERE cid = $myid; + } + } + foreach r $myrevisions { unset myrevmap($r) } + set pos [lsearch -exact $mychangesets $self] + set mychangesets [lreplace $mychangesets $pos $pos] + return + } + + # # ## ### ##### ######## ############# + ## State + + variable myid {} ; # Id of the cset for the persistent + # state. + variable myproject {} ; # Reference of the project object the + # changeset belongs to. + variable mytype {} ; # rev or sym, where the cset originated + # from. + variable mysrcid {} ; # Id of the metadata or symbol the cset + # is based on. + variable myrevisions {} ; # List of the file level revisions in + # the cset. + variable mynextmap {} ; # Dictionary mapping from the revisions + # to their successors. Cache to avoid + # loading this from the state more than + # once. + + # # ## ### ##### ######## ############# + ## Internal methods + + typevariable mycounter 0 ; # Id counter for csets. Last id used. + typevariable mycstype -array {} ; # Map cstypes to persistent ids. + + typemethod getcstypes {} { + foreach {tid name} [state run { + SELECT tid, name FROM cstype; + }] { set mycstype($name) $tid } + return + } + + typemethod loadcounter {} { + # Initialize the counter from the state + set mycounter [state one { SELECT MAX(cid) FROM changeset }] + return + } + + proc PullInternalSuccessorRevisions {dv revisions} { + upvar 1 $dv dependencies + set theset ('[join $revisions {','}]') + + foreach {rid child} [state run " + -- Primary children + SELECT R.rid, R.child + FROM revision R + WHERE R.rid IN $theset + AND R.child IS NOT NULL + AND R.child IN $theset + UNION + -- Transition NTDB to trunk + SELECT R.rid, R.dbchild + FROM revision R + WHERE R.rid IN $theset + AND R.dbchild IS NOT NULL + AND R.dbchild IN $theset + UNION + -- Secondary (branch) children + SELECT R.rid, B.brid + FROM revision R, revisionbranchchildren B + WHERE R.rid IN $theset + AND R.rid = B.rid + AND B.brid IN $theset + "] { + # Consider moving this to the integrity module. + if {$rid == $child} { + trouble internal "Revision $rid depends on itself." + } + lappend dependencies($rid) $child + } + } + + proc PullSuccessorRevisions {dv revisions} { + upvar 1 $dv dependencies + set theset ('[join $revisions {','}]') + + foreach {rid child} [state run " + -- Primary children + SELECT R.rid, R.child + FROM revision R + WHERE R.rid IN $theset + AND R.child IS NOT NULL + UNION + -- Transition NTDB to trunk + SELECT R.rid, R.dbchild + FROM revision R + WHERE R.rid IN $theset + AND R.dbchild IS NOT NULL + UNION + -- Secondary (branch) children + SELECT R.rid, B.brid + FROM revision R, revisionbranchchildren B + WHERE R.rid IN $theset + AND R.rid = B.rid + "] { + # Consider moving this to the integrity module. + if {$rid == $child} { + trouble internal "Revision $rid depends on itself." + } + lappend dependencies($rid) $child + } + } + + proc InitializeBreakState {revisions} { + upvar 1 pos pos cross cross range range depc depc delta delta \ + dependencies dependencies + + # First we create a map of positions to make it easier to + # determine whether a dependency crosses a particular index. + + array set pos {} + array set cross {} + array set depc {} + set range {} + set n 0 + foreach rev $revisions { + lappend range $n + set pos($rev) $n + set cross($n) 0 + incr n + } + + # Secondly we count the crossings per position, by iterating + # over the recorded internal dependencies. + + # Note: If the timestamps are badly out of order it is + # possible to have a backward successor dependency, + # i.e. with start > end. We may have to swap the indices + # to ensure that the following loop runs correctly. + # + # Note 2: start == end is not possible. It indicates a + # self-dependency due to the uniqueness of positions, + # and that is something we have ruled out already, see + # PullInternalSuccessorRevisions. + + foreach {rid child} [array get dependencies] { + set dkey [list $rid $child] + set start $pos($rid) + set end $pos($child) + set crosses {} + + if {$start > $end} { + while {$end < $start} { + lappend crosses $end + incr cross($end) + incr end + } + } else { + while {$start < $end} { + lappend crosses $start + incr cross($start) + incr start + } + } + set depc($dkey) $crosses + } + + InitializeDeltas $revisions + return + } + + proc InitializeDeltas {revisions} { + upvar 1 delta delta + + # Pull the timestamps for all revisions in the changesets and + # compute their deltas for use by the break finder. + + array set delta {} + array set stamp {} + + set theset ('[join $revisions {','}]') + foreach {rid time} [state run " + SELECT R.rid, R.date + FROM revision R + WHERE R.rid IN $theset + "] { + set stamp($rid) $time + } + + set n 0 + foreach rid [lrange $revisions 0 end-1] rnext [lrange $revisions 1 end] { + set delta($n) [expr {$stamp($rnext) - $stamp($rid)}] + incr n + } + return + } + + proc FindBestBreak {range} { + upvar 1 cross cross delta delta + + # Determine the best break location in the given range of + # positions. First we look for the locations with the maximal + # number of crossings. If there are several we look for the + # shortest time interval among them. If we still have multiple + # possibilities after that we select the earliest location + # among these. + + # Note: If the maximal number of crossings is 0 then the range + # has no internal dependencies, and no break location at + # all. This possibility is signaled via result -1. + + # Note: A range of length 1 or less cannot have internal + # dependencies, as that needs at least two revisions in + # the range. + + if {[llength $range] < 2} { return -1 } + + set max -1 + set best {} + + foreach location $range { + set crossings $cross($location) + if {$crossings > $max} { + set max $crossings + set best [list $location] + continue + } elseif {$crossings == $max} { + lappend best $location + } + } + + if {$max == 0} { return -1 } + if {[llength $best] == 1} { return [lindex $best 0] } + + set locations $best + set best {} + set min -1 + + foreach location $locations { + set interval $delta($location) + if {($min < 0) || ($interval < $min)} { + set min $interval + set best [list $location] + } elseif {$interval == $min} { + lappend best $location + } + } + + if {[llength $best] == 1} { return [lindex $best 0] } + + return [lindex [lsort -integer -increasing $best] 0] + } + + proc CutAt {location} { + upvar 1 cross cross depc depc + + # It was decided to split the changeset at the given + # location. This cuts a number of dependencies. Here we update + # the cross information so that the break finder has accurate + # data when we look at the generated fragments. + + set six [log visible? 6] + + foreach {dep range} [array get depc] { + # Check all dependencies still known, take their range and + # see if the break location falls within. + + Border $range s e + if {$location < $s} continue ; # break before range, ignore + if {$location > $e} continue ; # break after range, ignore. + + # This dependency crosses the break location. We remove it + # from the crossings counters, and then also from the set + # of known dependencies, as we are done with it. + + foreach loc $depc($dep) { incr cross($loc) -1 } + unset depc($dep) + + if {!$six} continue + + struct::list assign $dep parent child + log write 6 csets "Broke dependency [PD $parent] --> [PD $child]" + } + + return + } + + # Print identifying data for a revision (project, file, dotted rev + # number), for high verbosity log output. + + proc PD {id} { + foreach {p f r} [state run { + SELECT P.name , F.name, R.rev + FROM revision R, file F, project P + WHERE R.rid = $id + AND R.fid = F.fid + AND F.pid = P.pid + }] break + return "'$p : $f/$r'" + } + + # Printing one or more ranges, formatted, and only their border to + # keep the strings short. + + proc PRs {ranges} { + return [struct::list map $ranges [myproc PR]] + } + + proc PR {range} { + Border $range s e + return <${s}...${e}> + } + + proc Border {range sv ev} { + upvar 1 $sv s $ev e + set s [lindex $range 0] + set e [lindex $range end] + return + } + + # # ## ### ##### ######## ############# + + typevariable mychangesets {} ; # List of all known changesets. + typevariable myrevmap -array {} ; # Map from revisions to their changeset. + + typemethod all {} { + return $mychangesets + } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hastypeinfo no ; # no type introspection + pragma -hasinfo no ; # no object introspection + pragma -simpledispatch yes ; # simple fast dispatch + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::project { + namespace export rev + namespace eval rev { + namespace import ::vc::fossil::import::cvs::state + namespace import ::vc::tools::misc::* + namespace import ::vc::tools::trouble + namespace import ::vc::tools::log + log register csets + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::project::rev 1.0 +return
Added tools/cvs2fossil/lib/c2f_prevlink.tcl version [01734176b9]
@@ -1,1 +1,248 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## Helper class for the pass 6 cycle breaker. Each instance refers to +## three changesets A, B, and C, with A a predecessor of B, and B +## predecessor of C, and the whole part of a dependency cycle. + +## Instances analyse the file level dependencies which gave rise to +## the changeset dependencies of A, B, and C, with the results used by +## the cycle breaker algorithm to find a good location where to at +## least weaken and at best fully break the cycle. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require vc::tools::misc ; # Text formatting +package require vc::tools::trouble ; # Error reporting. +package require vc::tools::log ; # User feedback. +package require vc::fossil::import::cvs::state ; # State storage. +package require vc::fossil::import::cvs::project::rev ; # Project level changesets + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::project::revlink { + # # ## ### ##### ######## ############# + ## Public API + + constructor {prev cset next} { + set myprev $prev + set mycset $cset + set mynext $next + + # We perform the bulk of the analysis during construction. The + # file revisions held by the changeset CSET can be sorted into + # four categories. + + # 1. Revisions whose predecessors are not in PREV, nor are + # their successors found in NEXT. These revisions do not + # count, as they did not induce any of the two dependencies + # under consideration. They can be ignored. + + # 2. Revisions which have predecessors in PREV and sucessors + # in NEXT. They are called 'passthrough' in cvs2svn. They + # induce both dependencies under consideration and are thus + # critical in the creation of the cycle. As such they are + # also unbreakable :( + + # 3. Revisions which have predecessor in PREVE, but no + # successors in NEXT. As such they induced the incoming + # dependency, but not the outgoing one. + + # 4. Revisions which have no predecessors in PREVE, but their + # successors are in NEXT. As such they induced the outgoing + # dependency, but not the incoming one. + + # If we have no passthrough revisions then splitting the + # changeset between categories 3 and 4, with category 1 going + # wherever, will break the cycle. If category 2 revisions are + # present we can still perform the split, this will however + # not break the cycle, only weaken it. + + array set csetprevmap [Invert [$myprev nextmap]] + array set csetnextmap [$mycset nextmap] + + set prevrev [$myprev revisions] + set nextrev [$mynext revisions] + + foreach r [$mycset revisions] { + set rt [RT $r] + incr mycount($rt) + lappend mycategory($rt) $r + } + return + } + + # Result is TRUE if and only breaking myset will do some good. + method breakable {} { expr {$mycount(prev) || $mycount(next)} } + method passcount {} { return $mycount(pass) } + + method linkstomove {} { + # Return the number of revisions that would be moved should we + # split the changeset. + + set n [min2 $mycount(prev) $mycount(next)] + if {$n > 0 } { return $n } + return [max2 $mycount(prev) $mycount(next)] + } + + method betterthan {other} { + set sbreak [$self breakable] + set obreak [$other breakable] + + if {$sbreak && !$obreak} { return 1 } ; # self is better. + if {!$sbreak && $obreak} { return 0 } ; # self is worse. + + # Equality. Look at the counters. + # - Whichever has the lesser number of passthrough revisions + # is better, as more can be split off, weakening the cycle + # more. + # - Whichever has less links to move is better. + + set opass [$other passcount] + if {$mycount(pass) < $opass} { return 1 } ; # self is better. + if {$mycount(pass) > $opass} { return 0 } ; # self is worse. + + set smove [$self linkstomove] + set omove [$other linkstomove] + + if {$smove < $omove} { return 1 } ; # self is better. + + return 0 ; # Self is worse or equal, i.e. not better. + } + + method break {} { + if {![$self breakable]} { + trouble internal "Changeset <[$mycset id]> is not breakable." + } + + # One thing to choose when splitting CSET is where the + # revision in categories 1 and 2 (none and passthrough + # respectively) are moved to. This is done using the counters. + + if {!$mycount(prev)} { + # Nothing in category 3 => 1,2 go there, 4 the other. + set mycategory(prev) [concat $mycategory(none) $mycategory(pass)] + } elseif {!$mycount(next)} { + # Nothing in category 4 => 1,2 go there, 3 the other. + set mycategory(next) [concat $mycategory(none) $mycategory(pass)] + } elseif {$mycount(prev) < $mycount(next)} { + # Less predecessors than successors => 1,2 go to the + # sucessors. + set mycategory(next) [concat $mycategory(next) $mycategory(none) \ + $mycategory(pass)] + } else { + # Less successors than predecessors => 1,2 go to the + # predecessors. + set mycategory(next) [concat $mycategory(next) $mycategory(none) \ + $mycategory(pass)] + } + + # We now have the split in the mycategory(prev|next) + # elements. As part of the creation of the new changesets the + # old one is dropped from all databases, in and out of memory, + # and then destroyed. + + struct::list assign [$mycset data] project cstype cssrc + $mycset drop + $mycset destroy + + set newcsets {} + lappend newcsets [project::rev %AUTO% $project $cstype $cssrc $mycategory(prev)] + lappend newcsets [project::rev %AUTO% $project $cstype $cssrc $mycategory(next)] + + foreach c $newcsets { $c persist } + + return $newcsets + } + + # # ## ### ##### ######## ############# + ## State + + variable myprev {} ; # Reference to predecessor changeset in the link. + variable mycset {} ; # Reference to the main changeset of the link. + variable mynext {} ; # Reference to the successor changeset in the link. + + # Counters for the revision categories. + variable mycount -array { + none 0 + prev 0 + next 0 + pass 0 + } + # Lists of revisions for the various categories + variable mycategory -array { + none {} + prev {} + next {} + pass {} + } + + # # ## ### ##### ######## ############# + ## Internal methods + + proc RT {r} { + upvar 1 csetprevmap csetprevmap csetnextmap csetnextmap prevrev prevrev nextrev nextrev + + set inc [expr {[info exists csetprevmap($r)] + ? [struct::set size [struct::set intersect $csetprevmap($r) $prevrev]] + : 0}] + set out [expr {[info exists csetnextmap($r)] + ? [struct::set size [struct::set intersect $csetnextmap($r) $nextrev]] + : 0}] + + if {$inc && $out} { return pass } + if {$inc} { return prev } + if {$out} { return next } + return none + } + + proc Invert {dict} { + array set tmp {} + foreach {k values} $dict { + foreach v $values { lappend tmp($v) $k } + } + return [array get tmp] + } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hastypeinfo no ; # no type introspection + pragma -hasinfo no ; # no object introspection + pragma -simpledispatch yes ; # simple fast dispatch + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::project { + namespace export revlink + namespace eval revlink { + namespace import ::vc::fossil::import::cvs::state + namespace import ::vc::tools::misc::* + namespace import ::vc::tools::trouble + namespace eval project { + namespace import ::vc::fossil::import::cvs::project::rev + } + namespace import ::vc::tools::log + log register csets + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::project::revlink 1.0 +return
Added tools/cvs2fossil/lib/c2f_project.tcl version [39d1bb0e92]
@@ -1,1 +1,222 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## Project, part of a CVS repository. Multiple instances are possible. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require vc::fossil::import::cvs::file ; # CVS archive file. +package require vc::fossil::import::cvs::state ; # State storage. +package require vc::fossil::import::cvs::project::sym ; # Per project symbols. +package require vc::fossil::import::cvs::project::trunk ; # Per project trunk, main lod +package require vc::tools::log ; # User feedback +package require struct::list ; # Advanced list operations.. + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::project { + # # ## ### ##### ######## ############# + ## Public API + + constructor {path r} { + set mybase $path + set myrepository $r + set mytrunk [trunk %AUTO% $self] + set mysymbol([$mytrunk name]) $mytrunk + return + } + + method base {} { return $mybase } + method trunk {} { return $mytrunk } + + method printbase {} { + if {$mybase eq ""} {return <Repository>} + return $mybase + } + + method id {} { return $myid } + method setid {id} { set myid $id ; return } + + method addfile {rcs usr executable {fid {}}} { + set myfiles($rcs) [list $usr $executable $fid] + return + } + + method filenames {} { + return [lsort -dict [array names myfiles]] + } + + method files {} { + return [TheFiles] + } + + delegate method defauthor to myrepository + delegate method defcmessage to myrepository + delegate method trunkonly to myrepository + delegate method commitmessageof to myrepository + + method defmeta {bid aid cid} { + return [$myrepository defmeta $myid $bid $aid $cid] + } + + method getsymbol {name} { + if {![info exists mysymbol($name)]} { + set mysymbol($name) \ + [sym %AUTO% $name [$myrepository defsymbol $myid $name] $self] + } + return $mysymbol($name) + } + + method hassymbol {name} { + return [info exists mysymbol($name)] + } + + method purgeghostsymbols {} { + set changes 1 + while {$changes} { + set changes 0 + foreach {name symbol} [array get mysymbol] { + if {![$symbol isghost]} continue + log write 3 project "$mybase: Deleting ghost symbol '$name'" + $symbol destroy + unset mysymbol($name) + set changes 1 + } + } + return + } + + method determinesymboltypes {} { + foreach {name symbol} [array get mysymbol] { + $symbol determinetype + } + return + } + + # pass I persistence + method persist {} { + TheFiles ; # Force id assignment. + + state transaction { + # Project data first. Required so that we have its id + # ready for the files. + + state run { + INSERT INTO project (pid, name) + VALUES (NULL, $mybase); + } + set myid [state id] + + # Then all files, with proper backreference to their + # project. + + foreach rcs [lsort -dict [array names myfiles]] { + struct::list assign $myfiles($rcs) usr executable _fid_ + state run { + INSERT INTO file (fid, pid, name, visible, exec) + VALUES (NULL, $myid, $rcs, $usr, $executable); + } + $myfmap($rcs) setid [state id] + } + } + return + } + + # pass II persistence + method persistrev {} { + # Note: The per file information (incl. revisions and symbols) + # has already been saved and dropped. This was done + # immediately after processing it, i.e. as part of the main + # segment of the pass, to keep out use of memory under + # control. + # + # The repository level information has been saved as well too, + # just before saving the projects started. So now we just have + # to save the remaining project level parts to fix the + # left-over dangling references, which are the symbols. + + state transaction { + foreach {name symbol} [array get mysymbol] { + $symbol persistrev + } + } + return + } + + # # ## ### ##### ######## ############# + ## State + + variable mybase {} ; # Project directory. + variable myid {} ; # Project id in the persistent state. + variable mytrunk {} ; # Reference to the main line of + # development for the project. + variable myfiles -array {} ; # Maps the rcs archive paths to + # their user-visible files. + variable myfobj {} ; # File objects for the rcs archives + variable myfmap -array {} ; # Map rcs archive to their object. + variable myrepository {} ; # Repository the prject belongs to. + variable mysymbol -array {} ; # Map symbol names to project-level + # symbol objects. + + # # ## ### ##### ######## ############# + ## Internal methods + + proc TheFiles {} { + upvar 1 myfiles myfiles myfobj myfobj self self myfmap myfmap + if {![llength $myfobj]} { + set myfobj [EmptyFiles myfiles] + } + return $myfobj + } + + proc EmptyFiles {fv} { + upvar 1 $fv myfiles self self myfmap myfmap + set res {} + foreach rcs [lsort -dict [array names myfiles]] { + struct::list assign $myfiles($rcs) f executable fid + set file [file %AUTO% $fid $rcs $f $executable $self] + lappend res $file + set myfmap($rcs) $file + } + return $res + } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hastypeinfo no ; # no type introspection + pragma -hasinfo no ; # no object introspection + pragma -hastypemethods no ; # type is not relevant. + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs { + namespace export project + namespace eval project { + namespace import ::vc::tools::log + namespace import ::vc::fossil::import::cvs::file + namespace import ::vc::fossil::import::cvs::state + # Import not required, already a child namespace. + # namespace import ::vc::fossil::import::cvs::project::sym + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::project 1.0 +return
Added tools/cvs2fossil/lib/c2f_psym.tcl version [e97d1e5410]
@@ -1,1 +1,409 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## Symbols (Tags, Branches) per project. + +# # ## ### ##### ######## ############# ##################### +## 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::tools::misc ; # Text formatting. +package require vc::fossil::import::cvs::state ; # State storage. +package require struct::set ; # Set handling. + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::project::sym { + # # ## ### ##### ######## ############# + ## Public API + + constructor {name id project} { + set myname $name + set myid $id + set myproject $project + + # Count total number of symbols. + incr mynum + return + } + + method name {} { return $myname } + method id {} { return $myid } + + # # ## ### ##### ######## ############# + ## Symbol type + + method determinetype {} { + # This is done by a fixed heuristics, with guidance by the + # user in edge-cases. Contrary to cvs2svn which uses a big + # honking streagy class and rule objects. Keep it simple, we + # can expand later when we actually need all the complexity + # for configurability. + + # The following guidelines are applied: + # - Is usage unambigous ? + # - Was there ever a commit on the symbol ? + # - More used as tag, or more used as branch ? + # - At last, what has the user told us about it ? + # - Fail + + foreach rule { + UserConfig + Unambigous + HasCommits + VoteCounts + } { + set chosen [$self $rule] + if {$chosen eq $myundef} continue + $self MarkAs $rule $chosen + return + } + + # None of the above was able to decide which type to assign to + # the symbol. This is a fatal error preventing the execution + # of the passes after 'CollateSymbols'. + + incr myrulecount(Undecided_) + trouble fatal "Unable to decide how to convert symbol '$myname'" + return + } + + method markthetrunk {} { $self MarkAs IsTheTrunk $mybranch ; return } + + # # ## ### ##### ######## ############# + ## Symbol statistics + + method defcounts {tc bc cc} { + set mybranchcount $tc + set mytagcount $bc + set mycommitcount $cc + return + } + + method countasbranch {} { incr mybranchcount ; return } + method countastag {} { incr mytagcount ; return } + method countacommit {} { incr mycommitcount ; return } + + method blockedby {symbol} { + # Remember the symbol as preventing the removal of this + # symbol. Ot is a tag or branch that spawned from a revision + # on this symbol. + + struct::set include myblockers $symbol + return + } + + method possibleparent {symbol} { + if {[info exists mypparent($symbol)]} { + incr mypparent($symbol) + } else { + set mypparent($symbol) 1 + } + return + } + + method isghost {} { + # Checks if this symbol (as line of development) never + # existed. + + if {$mycommitcount > 0} { return 0 } + if {[llength $myblockers]} { return 0 } + if {[array size mypparent] > 0} { return 0 } + + return 1 + } + + # # ## ### ##### ######## ############# + + method persistrev {} { + set pid [$myproject id] + + state transaction { + state run { + INSERT INTO symbol ( sid, pid, name, type, tag_count, branch_count, commit_count) + VALUES ($myid, $pid, $myname, $myundef, $mytagcount, $mybranchcount, $mycommitcount); + } + foreach symbol $myblockers { + set bid [$symbol id] + state run { + INSERT INTO blocker (sid, bid) + VALUES ($myid, $bid); + } + } + foreach {symbol count} [array get mypparent] { + set pid [$symbol id] + state run { + INSERT INTO parent (sid, pid, n) + VALUES ($myid, $pid, $count); + } + } + } + return + } + + # # ## ### ##### ######## ############# + ## State + + variable myproject {} ; # Reference to the project object + # containing the symbol. + variable myname {} ; # The symbol's name + variable myid {} ; # Repository wide numeric id of the + # symbol. This implicitly encodes the + # project as well. + + variable mybranchcount 0 ; # Count how many uses as branch. + variable mytagcount 0 ; # Count how many uses as tag. + variable mycommitcount 0 ; # Count how many files did a commit on the symbol. + + variable myblockers {} ; # List (Set) of the symbols which block + # the exclusion of this symbol. + + variable mypparent -array {} ; # Maps from symbols to the number + # of files in which it could have + # been a parent of this symbol. + + variable mytype {} ; # The type chosen for the symbol to use in + # the conversion. + + # # ## ### ##### ######## ############# + + typemethod exclude {pattern} { + # Store the pattern in memory for use by the code doing type + # determination. + + lappend myexcludepattern [ProcessPattern $pattern exclusion] + return + } + + typemethod forcetag {pattern} { + # Store the pattern in memory for use by the code doing type + # determination. + + lappend myforcepattern [ProcessPattern $pattern force-tag] $mytag + return + } + + typemethod forcebranch {pattern} { + # Store the pattern in memory for use by the code doing type + # determination. + + lappend myforcepattern [ProcessPattern $pattern force-branch] $mybranch + return + } + + proc ProcessPattern {pattern label} { + if {[string match *:*:* $pattern]} { + # Bad syntax for the pattern, using multiple colons. + + trouble fatal "Bad $label pattern '$pattern'" + } elseif {![string match *:* $pattern]} { + # When only a symbol pattern is specified it applies to + # all projects. + + return [list * $pattern] + } else { + # Both project and symbol patterns are present, we split + # them apart now for storage and easier extraction later. + + return [split $pattern :] + } + } + + typevariable myexcludepattern {} ; # List of patterns specifying + # the symbols to exclude from + # conversion. Tags and/or + # branches. + + typevariable myforcepattern {} ; # List of patterns and types + # specifying which symbols to + # force to specific types. + + typemethod getsymtypes {} { + foreach {tid name} [state run { + SELECT tid, name FROM symtype; + }] { set mysymtype($tid) $name } + return + } + + # Keep the codes below in sync with 'pass::collrev/setup('symtype'). + typevariable myexcluded 0 ; # Code for symbols which are excluded. + typevariable mytag 1 ; # Code for symbols which are tags. + typevariable mybranch 2 ; # Code for symbols which are branches. + typevariable myundef 3 ; # Code for symbols of unknown type. + typevariable mysymtype -array {} ; # Map from type code to label for the log. + + typemethod undef {} { return $myundef } + typemethod excluded {} { return $myexcluded } + typemethod tag {} { return $mytag } + typemethod branch {} { return $mybranch } + + typemethod printrulestatistics {} { + log write 2 symbol "Rule usage statistics:" + + set fmt %[string length $mynum]s + set all 0 + + foreach key [lsort [array names myrulecount]] { + log write 2 symbol "* [format $fmt $myrulecount($key)] $key" + incr all $myrulecount($key) + } + + log write 2 symbol "= [format $fmt $all] total" + return + } + + # Statistics on how often each 'rule' was used to decide on the + # type of a symbol. + typevariable myrulecount -array { + HasCommits 0 + IsTheTrunk 0 + Unambigous 0 + Undecided_ 0 + UserConfig 0 + VoteCounts 0 + } + + typemethod printtypestatistics {} { + log write 2 symbol "Symbol type statistics:" + + set fmt %[string length $mynum]s + set all 0 + + foreach {stype splural n} [state run { + SELECT T.name, T.plural, COUNT (s.sid) + FROM symbol S, symtype T + WHERE S.type = T.tid + GROUP BY T.name + ORDER BY T.name + ; + }] { + log write 2 symbol "* [format $fmt $n] [sp $n $stype $splural]" + incr all $n + } + + log write 2 symbol "= [format $fmt $all] total" + return + } + + typevariable mynum 0 + + # # ## ### ##### ######## ############# + ## Internal methods + + method UserConfig {} { + set project [$myproject base] + + # First check if the user requested the exclusion of the + # symbol from conversion. + + foreach ex $myexcludepattern { + struct::list assign $ex pp sp + if {![string match $pp $project]} continue + if {![string match $sp $myname]} continue + return $myexcluded + } + + # If the symbol is not excluded further check if the user + # forces its conversion as a specific type. + + foreach {ex stype} $myforcepattern { + struct::list assign $ex pp sp + if {![string match $pp $project]} continue + if {![string match $sp $myname]} continue + return $stype + } + + # Nothing is forced, have the main system hand the symbol over + # to the regular heuristics. + + return $myundef + } + + method Unambigous {} { + # If a symbol is used unambiguously as a tag/branch, convert + # it as such. + + set istag [expr {$mytagcount > 0}] + set isbranch [expr {$mybranchcount > 0 || $mycommitcount > 0}] + + if {$istag && $isbranch} { return $myundef } + if {$istag} { return $mytag } + if {$isbranch} { return $mybranch } + + # Symbol was not used at all. + return $myundef + } + + method HasCommits {} { + # If there was ever a commit on the symbol, convert it as a + # branch. + + if {$mycommitcount > 0} { return $mybranch } + return $myundef + } + + method VoteCounts {} { + # Convert the symbol based on how often it was used as a + # branch/tag. Whichever happened more often determines how the + # symbol is converted. + + if {$mytagcount > $mybranchcount} { return $mytag } + if {$mytagcount < $mybranchcount} { return $mybranch } + return $myundef + } + + method MarkAs {label chosen} { + log write 3 symbol "\[$label\] Converting symbol '$myname' as $mysymtype($chosen)" + + set mytype $chosen + incr myrulecount($label) + + # This is stored directly into the database. + state run { + UPDATE symbol + SET type = $chosen + WHERE sid = $myid + ; + } + return + } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hastypeinfo no ; # no type introspection + pragma -hasinfo no ; # no object introspection + pragma -simpledispatch yes ; # simple fast dispatch + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::project { + namespace export sym + namespace eval sym { + namespace import ::vc::fossil::import::cvs::state + namespace import ::vc::tools::misc::* + namespace import ::vc::tools::trouble + namespace import ::vc::tools::log + log register symbol + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::project::sym 1.0 +return
Added tools/cvs2fossil/lib/c2f_ptrunk.tcl version [b20f9bb07d]
@@ -1,1 +1,88 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## Trunk, the special main line of development in a project. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::project::trunk { + # # ## ### ##### ######## ############# + ## Public API + + constructor {project} { + set mysymbol [$project getsymbol $myname] + set myid [$mysymbol id] + return + } + + destructor { + $mysymbol destroy + } + + method name {} { return $myname } + method id {} { return $myid } + method istrunk {} { return 1 } + method symbol {} { return $self } + + method forceid {id} { set myid $id ; return } + + method defcounts {tc bc cc} {} + + method countasbranch {} {} + method countastag {} {} + method countacommit {} {} + + method blockedby {symbol} {} + method possibleparent {symbol} {} + + method isghost {} { return 0 } + + delegate method persistrev to mysymbol + + method determinetype {} { $mysymbol markthetrunk } + + # # ## ### ##### ######## ############# + ## State + + typevariable myname :trunk: ; # Name shared by all trunk symbols. + variable myid {} ; # The trunk's symbol id. + variable mysymbol {} ; # The symbol underneath the trunk. + + # # ## ### ##### ######## ############# + ## Internal methods + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hastypeinfo no ; # no type introspection + pragma -hasinfo no ; # no object introspection + pragma -hastypemethods no ; # type is not relevant. + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::project { + namespace export trunk +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::project::trunk 1.0 +return
Added tools/cvs2fossil/lib/c2f_repository.tcl version [6cbcf7b826]
@@ -1,1 +1,472 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## Repository manager. Keeps projects and their files around. + +package provide vc::fossil::import::cvs::repository 1.0 + +# # ## ### ##### ######## ############# ##################### +## 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::tools::misc ; # Text formatting. +package require vc::tools::id ; # Indexing and id generation. +package require vc::fossil::import::cvs::project ; # CVS projects. +package require vc::fossil::import::cvs::state ; # State storage. +package require struct::list ; # List operations. +package require fileutil ; # File operations. + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::repository { + # # ## ### ##### ######## ############# + ## Public API + + typemethod base {path} { + # Could be checked, easier to defer to the overall validation. + set mybase $path + return + } + + typemethod add {path} { + # Most things cannot be checked immediately, as the base is + # not known while projects are added. We can and do check for + # uniqueness. We accept multiple occurences of a name, and + # treat them as a single project. + + if {[lsearch -exact $myprojpaths $path] >= 0} return + lappend myprojpaths $path + return + } + + typemethod trunkonly! {} { set mytrunkonly 1 ; return } + typemethod trunkonly {} { return $mytrunkonly } + + typemethod projects {} { + return [TheProjects] + } + + typemethod base? {} { return $mybase } + + typemethod validate {} { + if {![IsRepositoryBase $mybase msg]} { + trouble fatal $msg + # Without a good base directory checking any projects is + # wasted time, so we leave now. + return + } + foreach pp $myprojpaths { + if {![IsProjectBase $mybase/$pp $mybase/CVSROOT msg]} { + trouble fatal $msg + } + } + return + } + + typemethod defauthor {a} { $myauthor put $a } + typemethod defcmessage {cm} { $mycmsg put $cm } + typemethod defsymbol {pid name} { $mysymbol put [list $pid $name] } + typemethod defmeta {pid bid aid cid} { $mymeta put [list $pid $bid $aid $cid] } + + typemethod commitmessageof {mid} { + struct::list assign [$mymeta keyof $mid] pid bid aid cid + return [$mycmsg keyof $cid] + } + + # pass I results + typemethod printstatistics {} { + set prlist [TheProjects] + set npr [llength $prlist] + + log write 2 repository "Statistics: Scanned [nsp $npr project]" + + if {$npr > 1} { + set bmax [max [struct::list map $prlist [myproc .BaseLength]]] + incr bmax 2 + set bfmt %-${bmax}s + + set nmax [max [struct::list map $prlist [myproc .NFileLength]]] + set nfmt %${nmax}s + } else { + set bfmt %s + set nfmt %s + } + + set keep {} + foreach p $prlist { + set nfiles [llength [$p filenames]] + set line "Statistics: Project [format $bfmt \"[$p printbase]\"] : [format $nfmt $nfiles] [sp $nfiles file]" + if {$nfiles < 1} { + append line ", dropped" + } else { + lappend keep $p + } + log write 2 repository $line + } + + if {![llength $keep]} { + trouble warn "Dropped all projects" + } elseif {$npr == [llength $keep]} { + log write 2 repository "Keeping all projects" + } else { + log write 2 repository "Keeping [nsp [llength $keep] project]" + trouble warn "Dropped [nsp [expr {$npr - [llength $keep]}] {empty project}]" + } + + # Keep reduced set of projects. + set projects $keep + return + } + + # pass I persistence + typemethod persist {} { + ::variable myprojmap + state transaction { + foreach p [TheProjects] { + $p persist + set myprojmap([$p id]) $p + } + } + return + } + + typemethod load {} { + state transaction { + foreach {pid name} [state run { + SELECT pid, name FROM project ; + }] { + set project [project %AUTO% $name $type] + + lappend myprojpaths $name + lappend myprojects $project + set myprojmap($pid) $project + $project setid $pid + } + foreach {fid pid name visible exec} [state run { + SELECT fid, pid, name, visible, exec FROM file ; + }] { + $myprojmap($pid) addfile $name $visible $exec $fid + } + } + return + } + + # pass II results + typemethod printrevstatistics {} { + log write 2 repository "Revision statistics" + # number of revisions, symbols, repository wide, and per project ... + + set rcount [state one { SELECT COUNT (*) FROM revision }] + set tcount [state one { SELECT COUNT (*) FROM tag }] + set bcount [state one { SELECT COUNT (*) FROM branch }] + set scount [state one { SELECT COUNT (*) FROM symbol }] + set acount [state one { SELECT COUNT (*) FROM author }] + set ccount [state one { SELECT COUNT (*) FROM cmessage }] + set fmt %[string length [max [list $rcount $tcount $bcount $scount $acount $ccount]]]s + + log write 2 repository "Statistics: [format $fmt $rcount] [sp $rcount revision]" + log write 2 repository "Statistics: [format $fmt $tcount] [sp $tcount tag]" + log write 2 repository "Statistics: [format $fmt $bcount] [sp $bcount branch branches]" + log write 2 repository "Statistics: [format $fmt $scount] [sp $scount symbol]" + log write 2 repository "Statistics: [format $fmt $acount] [sp $acount author]" + log write 2 repository "Statistics: [format $fmt $ccount] [sp $ccount {log message}]" + + set prlist [TheProjects] + set npr [llength $prlist] + + if {$npr > 1} { + set bmax [max [struct::list map $prlist [myproc .BaseLength]]] + incr bmax 2 + set bfmt %-${bmax}s + } else { + set bfmt %s + } + + foreach p $prlist { + set pid [$p id] + set prefix "Statistics: Project [format $bfmt \"[$p printbase]\"]" + regsub -all {[^ ]} $prefix { } blanks + set sep " : " + + set rcount [state one { SELECT COUNT (*) FROM revision R, file F WHERE R.fid = F.fid AND F.pid = $pid }] + set tcount [state one { SELECT COUNT (*) FROM tag T, file F WHERE T.fid = F.fid AND F.pid = $pid }] + set bcount [state one { SELECT COUNT (*) FROM branch B, file F WHERE B.fid = F.fid AND F.pid = $pid }] + set scount [state one { SELECT COUNT (*) FROM symbol WHERE pid = $pid }] + set acount [state one { SELECT COUNT (*) FROM author WHERE aid IN (SELECT DISTINCT aid FROM meta WHERE pid = $pid) }] + set ccount [state one { SELECT COUNT (*) FROM cmessage WHERE cid IN (SELECT DISTINCT cid FROM meta WHERE pid = $pid) }] + + log write 2 repository "$prefix$sep[format $fmt $rcount] [sp $rcount revision]" + log write 2 repository "$blanks$sep[format $fmt $tcount] [sp $tcount tag]" + log write 2 repository "$blanks$sep[format $fmt $bcount] [sp $bcount branch branches]" + log write 2 repository "$blanks$sep[format $fmt $scount] [sp $scount symbol]" + log write 2 repository "$blanks$sep[format $fmt $acount] [sp $acount author]" + log write 2 repository "$blanks$sep[format $fmt $ccount] [sp $ccount {log message}]" + } + return + } + + # pass II persistence + typemethod persistrev {} { + state transaction { + SaveAuthors + SaveCommitMessages + # TODO: Save symbols of all projects (before the revisions + # in the projects, as they are referenced by the meta + # tuples) + SaveMeta + foreach p [TheProjects] { $p persistrev } + } + return + } + + typemethod loadsymbols {} { + state transaction { + # We load the symbol ids at large to have the mapping + # right from the beginning. + + foreach {sid pid name tc bc cc} [state run { + SELECT sid, pid, name, tag_count, branch_count, commit_count + FROM symbol + ; + }] { + $mysymbol map $sid [list $pid $name] + set project $myprojmap($pid) + + set force [$project hassymbol $name] + set symbol [$project getsymbol $name] + + # Forcing happens only for the trunks. + if {$force} { $symbol forceid $sid } + + # Set the loaded counts. + $symbol defcounts $tc $bc $cc + + # Note: The type is neither retrieved nor set, for + # this is used to load the pass II data, which means + # that everything is 'undefined' at this point anyway. + + # future: $symbol load (blockers, and parents) + } + } + return + } + + typemethod determinesymboltypes {} { + foreach project [TheProjects] { + $project determinesymboltypes + } + return + } + + typemethod projectof {pid} { + return $myprojmap($pid) + } + + + # pass IV+ results + typemethod printcsetstatistics {} { + log write 2 repository "Changeset statistics" + # number of revisions, symbols, repository wide, and per project ... + + set ccount [state one { SELECT COUNT (*) FROM changeset }] + set rcount [state one { SELECT COUNT (*) FROM changeset WHERE type = 0 }] + set scount [state one { SELECT COUNT (*) FROM changeset WHERE type = 1 }] + set fmt %[string length [max [list $ccount $rcount $scount]]]s + + log write 2 repository "Statistics: [format $fmt $ccount] [sp $ccount changeset]" + log write 2 repository "Statistics: [format $fmt $rcount] [sp $rcount {revision changeset}]" + log write 2 repository "Statistics: [format $fmt $scount] [sp $scount {symbol changeset}]" + + set prlist [TheProjects] + set npr [llength $prlist] + + if {$npr > 1} { + set bmax [max [struct::list map $prlist [myproc .BaseLength]]] + incr bmax 2 + set bfmt %-${bmax}s + } else { + set bfmt %s + } + + foreach p $prlist { + set pid [$p id] + set prefix "Statistics: Project [format $bfmt \"[$p printbase]\"]" + regsub -all {[^ ]} $prefix { } blanks + set sep " : " + + set ccount [state one { SELECT COUNT (*) FROM changeset WHERE pid = $pid }] + set rcount [state one { SELECT COUNT (*) FROM changeset WHERE pid = $pid AND type = 0 }] + set scount [state one { SELECT COUNT (*) FROM changeset WHERE pid = $pid AND type = 1 }] + + log write 2 repository "$prefix$sep[format $fmt $ccount] [sp $ccount changeset]" + log write 2 repository "$blanks$sep[format $fmt $rcount] [sp $rcount {revision changeset}]" + log write 2 repository "$blanks$sep[format $fmt $scount] [sp $scount {symbol changeset}]" + } + return + } + + # # ## ### ##### ######## ############# + ## State + + typevariable mybase {} ; # Base path to CVS repository. + typevariable myprojpaths {} ; # List of paths to all declared + # projects, relative to mybase. + typevariable myprojects {} ; # List of objects for all + # declared projects. + typevariable myprojmap -array {} ; # Map from project ids to their + # objects. + typevariable myauthor {} ; # Names of all authors found, + # maps to their ids. + typevariable mycmsg {} ; # All commit messages found, + # maps to their ids. + typevariable mymeta {} ; # Maps all meta data tuples + # (project, branch, author, + # cmessage) to their ids. + typevariable mysymbol {} ; # Map symbols identified by + # project and name to their + # id. This information is not + # saved directly. + typevariable mytrunkonly 0 ; # Boolean flag. Set by option + # processing when the user + # requested a trunk-only import + + # # ## ### ##### ######## ############# + ## Internal methods + + typeconstructor { + set myauthor [vc::tools::id %AUTO%] + set mycmsg [vc::tools::id %AUTO%] + set mymeta [vc::tools::id %AUTO%] + set mysymbol [vc::tools::id %AUTO%] + return + } + + proc .BaseLength {p} { + return [string length [$p printbase]] + } + + proc .NFileLength {p} { + return [string length [llength [$p filenames]]] + } + + proc IsRepositoryBase {path mv} { + ::variable mybase + upvar 1 $mv msg + if {![fileutil::test $mybase edr msg {CVS Repository}]} {return 0} + if {![fileutil::test $mybase/CVSROOT edr msg {CVS Admin Directory}]} {return 0} + return 1 + } + + proc IsProjectBase {path admin mv} { + upvar 1 $mv msg + if {![fileutil::test $path edr msg Project]} {return 0} + if { + ($path eq $admin) || + [string match $admin/* $path] + } { + set msg "Administrative subdirectory $path cannot be a project" + return 0 + } + return 1 + } + + proc TheProjects {} { + upvar 1 type type + ::variable myprojects + ::variable myprojpaths + + if {![llength $myprojects]} { + set myprojects [EmptyProjects $myprojpaths] + } + return $myprojects + } + + proc EmptyProjects {projpaths} { + ::variable mybase + upvar 1 type type + set res {} + if {[llength $projpaths]} { + foreach pp $projpaths { + lappend res [project %AUTO% $pp $type] + } + } else { + # Base is the single project. + lappend res [project %AUTO% "" $type] + } + return $res + } + + proc SaveAuthors {} { + ::variable myauthor + foreach {name aid} [$myauthor get] { + state run { + INSERT INTO author ( aid, name) + VALUES ($aid, $name); + } + } + return + } + + proc SaveCommitMessages {} { + ::variable mycmsg + foreach {text cid} [$mycmsg get] { + state run { + INSERT INTO cmessage ( cid, text) + VALUES ($cid, $text); + } + } + return + } + + proc SaveMeta {} { + ::variable mymeta + foreach {key mid} [$mymeta get] { + struct::list assign $key pid bid aid cid + state run { + INSERT INTO meta ( mid, pid, bid, aid, cid) + VALUES ($mid, $pid, $bid, $aid, $cid); + } + } + return + } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs { + namespace export repository + namespace eval repository { + namespace import ::vc::fossil::import::cvs::project + namespace import ::vc::fossil::import::cvs::state + namespace import ::vc::tools::misc::* + namespace import ::vc::tools::id + namespace import ::vc::tools::trouble + namespace import ::vc::tools::log + log register repository + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +return
Added tools/cvs2fossil/lib/c2f_state.tcl version [5356f2147d]
@@ -1,1 +1,195 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## State manager. Maintains the sqlite database used by all the other +## parts of the system, especially the passes and their support code, +## to persist and restore their state across invokations. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require fileutil ; # File operations. +package require sqlite3 ; # Database access. +package require vc::tools::trouble ; # Error reporting. +package require vc::tools::log ; # User feedback. + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::state { + # # ## ### ##### ######## ############# + ## Public API + + typemethod use {path} { + # Immediate validation. There are are two possibilities to + # consider. The path exists or it doesn't. + + # In the first case it has to be a readable and writable file, + # and it has to be a proper sqlite database. Further checks + # regarding the required tables will be done later, by the + # passes, during their setup. + + # In the second case we have to be able to create the file, + # and check that. This is done by opening it, sqlite will then + # try to create it, and may fail. + + if {[file exists $path]} { + if {![fileutil::test $path frw msg {cvs2fossil state}]} { + trouble fatal $msg + return + } + } + + if {[catch { + sqlite3 ${type}::TEMP $path + } res]} { + trouble fatal $res + return + } + + # A previously defined state database is closed before + # committing to the new definition. We do not store the path + # itself, this ensures that the file is _not_ cleaned up after + # a run. + + set mystate ${type}::STATE + set mypath {} + + catch { $mystate close } + rename ${type}::TEMP $mystate + + log write 2 state "is $path" + return + } + + typemethod setup {} { + # If, and only if no state database was defined by the user + # then it is now the time to create our own using a tempfile. + + if {$mystate ne ""} return + + set mypath [fileutil::tempfile cvs2fossil_state_] + set mystate ${type}::STATE + sqlite3 $mystate $mypath + + log write 2 state "using $mypath" + return + } + + typemethod release {} { + log write 2 state release + ${type}::STATE close + if {$mypath eq ""} return + file delete $mypath + return + } + + typemethod writing {name definition} { + # Method for a user to declare a table its needs for storing + # persistent state, and the expected structure. A possibly + # previously existing definition is dropped. + + log write 0 state "writing $name" ; # TODO move to level 5 or so + + $mystate transaction { + catch { $mystate eval "DROP TABLE $name" } + $mystate eval "CREATE TABLE $name ( $definition )" + } + return + } + + typemethod reading {name} { + log write 0 state "reading $name" ; # TODO move to level 5 or so + + # Method for a user to declare a table it wishes to read + # from. A missing table is an internal error causing an + # immediate exit. + + set found [llength [$mystate eval { + SELECT name + FROM sqlite_master + WHERE type = 'table' + AND name = $name + ; + }]] + + if {$found} return + + trouble internal "The required table \"$name\" is not defined." + # Not reached + return + } + + typemethod discard {name} { + # Method for a user to remove outdated information from the + # persistent state, table by table. + + log write 0 state "discard $name" ; # TODO move to level 5 or so + + $mystate transaction { + catch { $mystate eval "DROP TABLE $name" } + } + return + } + + typemethod run {args} { + return [uplevel 1 [linsert $args 0 $mystate eval]] + } + + typemethod one {args} { + return [lindex [uplevel 1 [linsert $args 0 $mystate eval]] 0] + } + + typemethod transaction {script} { + return [uplevel 1 [list $mystate transaction $script]] + } + + typemethod id {} { + return [$mystate last_insert_rowid] + } + + # # ## ### ##### ######## ############# + ## State + + typevariable mystate {} ; # Sqlite database (command) holding the converter state. + typevariable mypath {} ; # Path to the database, for cleanup of a temp database. + + # # ## ### ##### ######## ############# + ## Internal methods + + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs { + namespace export state + namespace eval state { + namespace import ::vc::tools::trouble + namespace import ::vc::tools::log + log register state + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs::state 1.0 +return
Added tools/cvs2fossil/lib/cvs2fossil.tcl version [516ad35538]
@@ -1,1 +1,88 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## Main package of the cvs conversion/import facility. Loads the +## required pieces and controls their interaction. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system + +# # ## ### ##### ######## ############# ##################### +## Passes. The order in which the various passes are loaded is +## important. It is the same order in which they will +## register, and then be run in. + +package require vc::fossil::import::cvs::pass::collar ; # Coll'ect Ar'chives. +package require vc::fossil::import::cvs::pass::collrev ; # Coll'ect Rev'isions. +package require vc::fossil::import::cvs::pass::collsym ; # Coll'ate Sym'bols +package require vc::fossil::import::cvs::pass::filtersym ; # Filter' Sym'bols + +# Note: cvs2svn's SortRevisionSummaryPass and SortSymbolSummaryPass +# are not implemented by us. They are irrelevant due to our use +# of a relational database proper for the persistent state, +# allowing us to sort the data on the fly as we need it. + +package require vc::fossil::import::cvs::pass::initcsets ; # Init'ialize C'hange'Sets +package require vc::fossil::import::cvs::pass::breakrcycle ; # Break' R'evision Cycle's + +# Note: cvs2svn's RevisionTopologicalSortPass is not a separate pass, +# but was subsumed by the previous pass, by immediately saving +# the order of consumed graph nodes to 'csorder'. + +package require vc::fossil::import::cvs::pass::breakscycle ; # Break' S'ymbol Cycle's +package require vc::fossil::import::cvs::pass::breakacycle ; # Break' A'll Cycle's + +# # ## ### ##### ######## ############# ##################### +## Support for passes etc. + +package require vc::fossil::import::cvs::option ; # Cmd line parsing & database +package require vc::fossil::import::cvs::pass ; # Pass management +package require vc::tools::log ; # User feedback + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs { + # # ## ### ##### ######## ############# + ## Public API, Methods + + typemethod run {arguments} { + # Run a series of passes over the cvs repository to extract, + # filter, and order its historical information. Which passes + # are actually run is determined through the specified options + # and their defaults. + + option process $arguments + pass run + + vc::tools::log write 0 cvs2fossil Done + return + } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::fossil::import::cvs 1.0 +return
Added tools/cvs2fossil/lib/id.tcl version [ad0171bebe]
@@ -1,1 +1,64 @@ +# # ## ### ##### ######## ############# + +## A simple class for handling an in-memory index mapping from +## arbitrary strings to a small numeric id. Can be queried in reverse +## too, returning the string for the id. + +## Id's are starting from 1. + +# # ## ### ##### ######## ############# +## Requirements. + +package require Tcl ; # Runtime. +package require snit ; # OO runtime. + +# # ## ### ##### ######## ############# +## Implementation. + +snit::type ::vc::tools::id { + # # ## ### ##### ######## ############# + + constructor {} {} + + # # ## ### ##### ######## ############# + ## Public API. + ## - Put data into the index, incl. query for id of key. + ## - Lookup data for id. + + method put {key} { + if {[info exists mydata($key)]} { return $mydata($key) } + incr mycounter + + set mydata($key) $mycounter + set myinvert($mycounter) $key + + return $mycounter + } + + # Explicitly load the database with a mapping. + method map {id key} { + set mydata($key) $id + set myinvert($id) $key + } + + method keyof {id} { return $myinvert($id) } + method get {} { return [array get mydata] } + + # # ## ### ##### ######## ############# + ## Internal. State. + + variable mydata -array {} ; # Map data -> id + variable myinvert -array {} ; # Map id -> data + variable mycounter 0 ; # Counter for id generation. + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::tools { + namespace export id +} + +# # ## ### ##### ######## ############# +## Ready. +package provide vc::tools::id 1.0
Added tools/cvs2fossil/lib/log.tcl version [2d2937d11b]
@@ -1,1 +1,168 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## Utility package, basic user feedback + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime +package require snit ; # OO system. + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::tools::log { + # # ## ### ##### ######## ############# + ## Public API, Methods + + # Write the message 'text' to log, for the named 'system'. The + # message is written if and only if the message verbosity is less + # or equal the chosen verbosity. A message of verbosity 0 cannot + # be blocked. + + typemethod write {verbosity system text} { + if {$verbosity > $myloglevel} return + uplevel #0 [linsert $mylogcmd end write [System $system] $text] + return + } + + # Similar to write, especially in the handling of the verbosity, + # to drive progress displays. It signals that for some long + # running operation we are at tick 'n' of at most 'max' ticks. An + # empty 'max' indicates an infinite progress display. + + typemethod progress {verbosity system n max} { + if {$verbosity > $myloglevel} return + uplevel #0 [linsert $mylogcmd end progress [System $system] $n $max] + return + } + + typemethod visible? {verbosity} { + return [expr {$verbosity <= $myloglevel}] + } + + # # ## ### ##### ######## ############# + # Public API, Administrative methods + + # Set verbosity to the chosen 'level'. Only messages with a level + # less or equal to this one will be shown. + + typemethod verbosity {level} { + if {$level < 1} {set level 0} + set myloglevel $level + return + } + + typemethod verbose {} { + incr myloglevel + return + } + + typemethod quiet {} { + if {$myloglevel < 1} return + incr myloglevel -1 + return + } + + # Query the currently set verbosity. + + typemethod verbosity? {} { + return $myloglevel + } + + # Set the log callback handling the actual output of messages going + # through the package. + + typemethod command {cmdprefix} { + variable mylogcmd $cmdprefix + return + } + + # Register a system name, to enable tabular formatting. This is + # done by setting up a format specifier with a proper width. This + # is handled in the generation command, before the output callback + # is invoked. + + typemethod register {name} { + set nlen [string length $name] + if {$nlen < $mysyslen} return + set mysyslen $nlen + set mysysfmt %-${mysyslen}s + return + } + + # # ## ### ##### ######## ############# + ## Internal, state + + typevariable myloglevel 2 ; # Some verbosity, not too much + typevariable mylogcmd ::vc::tools::log::OUT ; # Standard output to stdout. + typevariable mysysfmt %s ; # Non-tabular formatting. + typevariable mysyslen 0 ; # Ditto. + + # # ## ### ##### ######## ############# + ## Internal, helper methods (formatting, dispatch) + + proc System {s} { + ::variable mysysfmt + return [format $mysysfmt $s] + } + + # # ## ### ##### ######## ############# + ## Standard output callback, module internal + + # Dispatch to the handlers of the possible operations. + + proc OUT {op args} { + eval [linsert $args 0 ::vc::tools::log::OUT/$op] + return + } + + # Write handler. Each message is a line. + + proc OUT/write {system text} { + puts "$system $text" + return + } + + # Progress handler. Uses \r to return to the beginning of the + # current line without advancing. + + proc OUT/progress {system n max} { + if {$max eq {}} { + puts -nonewline "$system $n\r" + } else { + puts -nonewline "$system [format %[string length $max]s $n]/$max\r" + } + flush stdout + return + } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::tools { + namespace export log +} + +# ----------------------------------------------------------------------------- +# Ready +package provide vc::tools::log 1.0 +return
Added tools/cvs2fossil/lib/misc.tcl version [d837793c99]
@@ -1,1 +1,100 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## Utilities for various things: text formatting, max, ... + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime + +# # ## ### ##### ######## ############# ##################### +## + +namespace eval ::vc::tools::misc { + # # ## ### ##### ######## ############# + ## Public API, Methods + + # Choose singular vs plural forms of a word based on a number. + + proc sp {n singular {plural {}}} { + if {$n == 1} {return $singular} + if {$plural eq ""} {set plural ${singular}s} + return $plural + } + + # As above, with the number automatically put in front of the + # string. + + proc nsp {n singular {plural {}}} { + return "$n [sp $n $singular $plural]" + } + + # Find maximum/minimum in a list. + + proc max {list} { + set max -1 + foreach e $list { + if {$e < $max} continue + set max $e + } + return $max + } + + proc min {list} { + set min {} + foreach e $list { + if {$min == {}} { + set min $e + } elseif {$e > $min} continue + set min $e + } + return $min + } + + proc max2 {a b} { + if {$a > $b} { return $a } + return $b + } + + proc min2 {a b} { + if {$a < $b} { return $a } + return $b + } + + proc ldelete {lv item} { + upvar 1 $lv list + set pos [lsearch -exact $list $item] + if {$pos < 0} return + set list [lreplace $list $pos $pos] + return + } + + # Delete item from list by name + + proc striptrailingslash {path} { + # split and rejoin gets rid of a traling / character. + return [eval [linsert [file split $path] 0 file join]] + } + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::tools::misc { + namespace export sp nsp max min max2 min2 ldelete striptrailingslash +} + +# ----------------------------------------------------------------------------- +# Ready +package provide vc::tools::misc 1.0 +return
Added tools/cvs2fossil/lib/pkgIndex.tcl version [326b42f768]
@@ -1,1 +1,36 @@ - +# # ## ### ##### ######## ############# ##################### +## Package management. +## Index of the local packages required by cvs2fossil +# # ## ### ##### ######## ############# ##################### +if {![package vsatisfies [package require Tcl] 8.4]} return +package ifneeded vc::fossil::import::cvs 1.0 [list source [file join $dir cvs2fossil.tcl]] +package ifneeded vc::fossil::import::cvs::file 1.0 [list source [file join $dir c2f_file.tcl]] +package ifneeded vc::fossil::import::cvs::file::lodmgr 1.0 [list source [file join $dir c2f_flodmgr.tcl]] +package ifneeded vc::fossil::import::cvs::file::rev 1.0 [list source [file join $dir c2f_frev.tcl]] +package ifneeded vc::fossil::import::cvs::file::sym 1.0 [list source [file join $dir c2f_fsym.tcl]] +package ifneeded vc::fossil::import::cvs::file::trunk 1.0 [list source [file join $dir c2f_ftrunk.tcl]] +package ifneeded vc::fossil::import::cvs::option 1.0 [list source [file join $dir c2f_option.tcl]] +package ifneeded vc::fossil::import::cvs::integrity 1.0 [list source [file join $dir c2f_integrity.tcl]] +package ifneeded vc::fossil::import::cvs::pass 1.0 [list source [file join $dir c2f_pass.tcl]] +package ifneeded vc::fossil::import::cvs::pass::collar 1.0 [list source [file join $dir c2f_pcollar.tcl]] +package ifneeded vc::fossil::import::cvs::pass::collrev 1.0 [list source [file join $dir c2f_pcollrev.tcl]] +package ifneeded vc::fossil::import::cvs::pass::collsym 1.0 [list source [file join $dir c2f_pcollsym.tcl]] +package ifneeded vc::fossil::import::cvs::pass::filtersym 1.0 [list source [file join $dir c2f_pfiltersym.tcl]] +package ifneeded vc::fossil::import::cvs::pass::initcsets 1.0 [list source [file join $dir c2f_pinitcsets.tcl]] +package ifneeded vc::fossil::import::cvs::pass::breakrcycle 1.0 [list source [file join $dir c2f_pbreakrcycle.tcl]] +package ifneeded vc::fossil::import::cvs::pass::breakscycle 1.0 [list source [file join $dir c2f_pbreakscycle.tcl]] +package ifneeded vc::fossil::import::cvs::pass::breakacycle 1.0 [list source [file join $dir c2f_pbreakacycle.tcl]] +package ifneeded vc::fossil::import::cvs::cyclebreaker 1.0 [list source [file join $dir c2f_cyclebreaker.tcl]] +package ifneeded vc::fossil::import::cvs::project 1.0 [list source [file join $dir c2f_project.tcl]] +package ifneeded vc::fossil::import::cvs::project::lodmgr 1.0 [list source [file join $dir c2f_plodmgr.tcl]] +package ifneeded vc::fossil::import::cvs::project::rev 1.0 [list source [file join $dir c2f_prev.tcl]] +package ifneeded vc::fossil::import::cvs::project::revlink 1.0 [list source [file join $dir c2f_prevlink.tcl]] +package ifneeded vc::fossil::import::cvs::project::sym 1.0 [list source [file join $dir c2f_psym.tcl]] +package ifneeded vc::fossil::import::cvs::project::trunk 1.0 [list source [file join $dir c2f_ptrunk.tcl]] +package ifneeded vc::fossil::import::cvs::repository 1.0 [list source [file join $dir c2f_repository.tcl]] +package ifneeded vc::fossil::import::cvs::state 1.0 [list source [file join $dir c2f_state.tcl]] +package ifneeded vc::rcs::parser 1.0 [list source [file join $dir rcsparser.tcl]] +package ifneeded vc::tools::log 1.0 [list source [file join $dir log.tcl]] +package ifneeded vc::tools::misc 1.0 [list source [file join $dir misc.tcl]] +package ifneeded vc::tools::trouble 1.0 [list source [file join $dir trouble.tcl]] +package ifneeded vc::tools::id 1.0 [list source [file join $dir id.tcl]]
Added tools/cvs2fossil/lib/rcsparser.tcl version [93e4a1e5a5]
@@ -1,1 +1,485 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +# A tool package, provides a parser for RCS archive files. This parser +# is implemented via recursive descent. It is not only given a file to +# process, but also a 'sink', an object it calls out to at important +# places of the parsing process to either signal an event and/or +# convey gathered information to it. The sink is responsible for the +# actual processing of the data in whatever way it desires. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require fileutil ; # File utilities. +package require vc::tools::log ; # User feedback. +package require struct::list ; # Advanced list ops. + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::rcs::parser { + # # ## ### ##### ######## ############# + ## Public API + + typemethod process {path sink} { + Initialize $path $sink + Call begin + Admin ; Deltas ; Description ; DeltaTexts + Call done + return + } + + # # ## ### ##### ######## ############# + ## Internal methods, recursive descent, syntactical processing + + proc Admin {} { + Head ; PrincipalBranch ; Access ; Symbols + Locks ; Strictness ; FileComment ; Expand + Call admindone + return + } + + # # ## ### ##### ######## ############# + + proc Head {} { + RequiredLiteral head + RequiredNumber -> head + Semicolon + Call sethead $head + return + } + + proc PrincipalBranch {} { + if {![OptionalLiteral branch]} return + RequiredNumber -> branch + Semicolon + Call setprincipalbranch $branch + return + } + + proc Access {} { + RequiredLiteral access ; + Semicolon + return + } + + proc Symbols {} { + RequiredLiteral symbols + while {[Ident -> symbol]} { + if { + *$} $symbol] || + [string match */ $symbol] + } { + Rewind + Bad {symbol name} + } + RequiredNumber -> rev + Call deftag $symbol $rev + } + Semicolon + return + } + + proc Locks {} { + # Not saving locks. + RequiredLiteral locks + while {[Ident -> symbol]} { + RequiredNumber -> l + } + Semicolon + return + } + + proc Strictness {} { + # Not saving strictness + if {![OptionalLiteral strict]} return + Semicolon + return + } + + proc FileComment {} { + if {![OptionalLiteral comment]} return + if {![OptionalString -> c]} return + Semicolon + Call setcomment $c + return + } + + proc Expand {} { + # Not saving expanded keywords + if {![OptionalLiteral expand]} return + if {![OptionalString -> dummy]} return + Semicolon + return + } + + # # ## ### ##### ######## ############# + + proc Deltas {} { + set ok [OptionalNumber -> rev] + while {$ok} { + Date -> d + Author -> a + State -> s + Branches -> b + NextRev -> n + Call def $rev $d $a $s $n $b + + # Check if this is followed by a revision number or the + # literal 'desc'. If neither we consume whatever is there + # until the next semicolon, as it has to be a 'new + # phrase'. Otherwise, for a revision number we loop back + # and consume that revision, and lastly for 'desc' we stop + # completely as this signals the end of the revision tree + # and the beginning of the deltas. + + while {1} { + set ok [OptionalNumber -> rev] + if {$ok} break + + if {[LiteralPeek desc]} { + set ok 0 + break + } + + Anything -> dummy + Semicolon + } + } + Call defdone + return + } + + # # ## ### ##### ######## ############# + + proc Date {_ dv} { + upvar 1 $dv d + RequiredLiteral date + RequiredNumber -> d + Semicolon + + struct::list assign [split $d .] year month day hour min sec + if {$year < 100} {incr year 1900} + set d [clock scan "${year}-${month}-${day} ${hour}:${min}:${sec}"] + return + } + + proc Author {_ av} { + upvar 1 $av a + RequiredLiteral author + Anything -> a + Semicolon + return + } + + proc State {_ sv} { + upvar 1 $sv s + RequiredLiteral state + Anything -> s + Semicolon + return + } + + proc Branches {_ bv} { + upvar 1 $bv b + RequiredLiteral branches + Anything -> b + Semicolon + return + } + + proc NextRev {_ nv} { + upvar 1 $nv n + RequiredLiteral next + Anything -> n + Semicolon + return + } + + # # ## ### ##### ######## ############# + + proc Description {} { + upvar 1 data data res res + RequiredLiteral desc + RequiredString -> d + Call setdesc $d + return + } + + # # ## ### ##### ######## ############# + + proc DeltaTexts {} { + while {[OptionalNumber -> rev]} { + RequiredLiteral log + RequiredString -> cmsg + if {[regexp {[\000-\010\013\014\016-\037]} $cmsg]} { + #Rewind + #Bad "log message for $rev contains at least one control character" + } + + RequiredLiteral text + RequiredStringRange -> delta + Call extend $rev $cmsg $delta + } + return + } + + # # ## ### ##### ######## ############# + ## Internal methods, lexiographical processing + + proc Semicolon {} { + ::variable mydata + ::variable mypos + + set ok [regexp -start $mypos -indices -- {\A\s*;\s*} $mydata match] + if {!$ok} { Expected ';' } + + SkipOver match + return + } + + proc RequiredLiteral {name} { + ::variable mydata + ::variable mypos + + set pattern "\\A\\s*$name\\s*" + set ok [regexp -start $mypos -indices -- $pattern $mydata match] + if {!$ok} { Expected '$name' } + + SkipOver match + return + } + + proc OptionalLiteral {name} { + ::variable mydata + ::variable mypos + + set pattern "\\A\\s*$name\\s*" + set ok [regexp -start $mypos -indices -- $pattern $mydata match] + if {!$ok} { return 0 } + + SkipOver match + return 1 + } + + proc LiteralPeek {name} { + ::variable mydata + ::variable mypos + + set pattern "\\A\\s*$name\\s*" + set ok [regexp -start $mypos -indices -- $pattern $mydata match] + if {!$ok} { return 0 } + + # NO - SkipOver match - Only looking ahead here. + return 1 + } + + proc RequiredNumber {_ v} { + upvar 1 $v value + ::variable mydata + ::variable mypos + + set pattern {\A\s*((\d|\.)+)\s*} + set ok [regexp -start $mypos -indices -- $pattern $mydata match v] + if {!$ok} { Expected id } + + Extract $v -> value + SkipOver match + return + } + + proc OptionalNumber {_ v} { + upvar 1 $v value + ::variable mydata + ::variable mypos + + set pattern {\A\s*((\d|\.)+)\s*} + set ok [regexp -start $mypos -indices -- $pattern $mydata match v] + if {!$ok} { return 0 } + + Extract $v -> value + SkipOver match + return 1 + } + + proc RequiredString {_ v} { + upvar 1 $v value + ::variable mydata + ::variable mypos + + set ok [regexp -start $mypos -indices -- {\A\s*@(([^@]*(@@)*)*)@\s*} $mydata match v] + if {!$ok} { Expected string } + + Extract $v -> value + set value [string map {@@ @} $value] + SkipOver match + return + } + + proc RequiredStringRange {_ v} { + upvar 1 $v value + ::variable mydata + ::variable mypos + + set ok [regexp -start $mypos -indices -- {\A\s*@(([^@]*(@@)*)*)@\s*} $mydata match value] + if {!$ok} { Expected string } + + SkipOver match + return + } + + proc OptionalString {_ v} { + upvar 1 $v value + ::variable mydata + ::variable mypos + + set ok [regexp -start $mypos -indices -- {\A\s*@(([^@]*(@@)*)*)@\s*} $mydata match v] + if {!$ok} { return 0 } + + Extract $v -> value + set value [string map {@@ @} $value] + SkipOver match + return 1 + } + + proc Ident {_ v} { + upvar 1 $v value + ::variable mydata + ::variable mypos + + set ok [regexp -start $mypos -indices -- {\A\s*;\s*} $mydata] + if {$ok} { return 0 } + + set ok [regexp -start $mypos -indices -- {\A\s*([^:]*)\s*:\s*} $mydata match v] + if {!$ok} { return 0 } + + Extract $v -> value + SkipOver match + return 1 + } + + proc Anything {_ v} { + upvar 1 $v value + ::variable mydata + ::variable mypos + + regexp -start $mypos -indices -- {\A\s*([^;]*)\s*} $mydata match v + + Extract $v -> value + SkipOver match + return + } + + # # ## ### ##### ######## ############# + ## Internal methods, input handling + + proc Extract {range _ v} { + upvar 1 $v value + ::variable mydata + struct::list assign $range s e + set value [string range $mydata $s $e] + return + } + + proc SkipOver {mv} { + # Note: The indices are absolute!, not relative to the start + # location. + upvar 1 $mv match + ::variable mypos + ::variable mysize + ::variable mylastpos + + struct::list assign $match s e + #puts "<$s $e> [info level -1]" + + set mylastpos $mypos + set mypos $e + incr mypos + + log progress 2 rcs $mypos $mysize + #puts $mypos/$mysize + return + } + + proc Rewind {} { + ::variable mypos + ::variable mylastpos + + set mypos $mylastpos + return + } + + proc Expected {x} { + ::variable mydata + ::variable mypos + set e $mypos ; incr e 30 + return -code error -errorcode vc::rcs::parser \ + "Expected $x @ '[string range $mydata $mypos $e]...'" + } + + proc Bad {x} { + ::variable mydata + ::variable mypos + set e $mypos ; incr e 30 + return -code error -errorcode vc::rcs::parser \ + "Bad $x @ '[string range $mydata $mypos $e]...'" + } + + # # ## ### ##### ######## ############# + ## Setup, callbacks. + + proc Initialize {path sink} { + ::variable mypos 0 + ::variable mydata [fileutil::cat -encoding binary $path] + ::variable mysize [file size $path] + ::variable mysink $sink + return + } + + proc Call {args} { + ::variable mysink + set cmd $mysink + foreach a $args { lappend cmd $a } + eval $cmd + return + } + + # # ## ### ##### ######## ############# + ## Configuration + + typevariable mydata {} ; # Rcs archive contents to process + typevariable mysize 0 ; # Length of contents + typevariable mysink {} ; # Sink to report to + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::rcs { + namespace export parser + namespace eval parser { + namespace import ::vc::tools::log + log register rcs + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::rcs::parser 1.0 +return
Added tools/cvs2fossil/lib/trouble.tcl version [f653273970]
@@ -1,1 +1,124 @@ +## -*- 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 +# # ## ### ##### ######## ############# ##################### + +## Utility package, error reporting on top of the log package. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require vc::tools::log ; # Basic log generation. +package require snit ; # OO system. + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::tools::trouble { + # # ## ### ##### ######## ############# + ## Public API, Methods + + typemethod internal {text} { + foreach line [split $text \n] { $type fatal "INTERNAL ERROR! $line" } + exit 1 + } + + typemethod fatal {text} { + lappend myfatal $text + return + } + + typemethod warn {text} { + lappend mywarn $text + log write 0 trouble $text + return + } + + typemethod info {text} { + lappend myinfo $text + return + } + + typemethod show {} { + foreach m $myinfo { log write 0 "" $m } + foreach m $mywarn { log write 0 warning $m } + foreach m $myfatal { log write 0 fatal $m } + return + } + + typemethod ? {} { + return [expr { + [llength $myinfo] || + [llength $mywarn] || + [llength $myfatal] + }] + } + + typemethod abort? {} { + if { + ![llength $myinfo] && + ![llength $mywarn] && + ![llength $myfatal] + } return + + # Frame the pending messages to make them more clear as the + # cause of the abort. + + set myinfo [linsert $myinfo 0 "" "Encountered problems." ""] + lappend myfatal "Stopped due to problems." + + # We have error messages to print, so stop now. + exit 1 + } + + # # ## ### ##### ######## ############# + ## Internal, state + + typevariable myinfo {} + typevariable mywarn {} + typevariable myfatal {} + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +# # ## ### ##### ######## ############# ##################### +## Internal. Special. Set up a hook into the application exit, to show +## the remembered messages, before passing through the regular command. + +rename ::exit ::vc::tools::trouble::EXIT +proc ::exit {{status 0}} { + ::vc::tools::trouble show + ::vc::tools::trouble::EXIT $status + # Not reached. + return +} + +namespace eval ::vc::tools { + namespace eval trouble {namespace import ::vc::tools::log } + trouble::log register "" + trouble::log register fatal + trouble::log register trouble + trouble::log register warning + namespace export trouble +} + +# # ## ### ##### ######## ############# ##################### +## Ready +package provide vc::tools::trouble 1.0 +return
Deleted tools/import-cvs.tcl version [8655038b63]
Deleted tools/lib/cvs.tcl version [e947a38eb8]
Deleted tools/lib/cvs_cmd.tcl version [47fea6fc5d]
Deleted tools/lib/cvs_csets.tcl version [c6beb0fbbb]
Deleted tools/lib/cvs_files.tcl version [24c1271ded]
Deleted tools/lib/cvs_timeline.tcl version [09c55e80b2]
Deleted tools/lib/fossil.tcl version [6aae29bf14]
Deleted tools/lib/fossil_cmd.tcl version [49d37a1b8b]
Deleted tools/lib/import_map.tcl version [44f7107846]
Deleted tools/lib/import_statistics.tcl version [afdce6cc23]
Deleted tools/lib/importcvs.tcl version [d5f1e97a32]
Deleted tools/lib/log.tcl version [edfb9cfb1e]
Deleted tools/lib/pkgIndex.tcl version [48d829569b]
Deleted tools/lib/rcsparser.tcl version [564a99c1a7]
Deleted tools/lib/trouble.tcl version [a4a0b8a72b]
Added www/CollRev1.gif version [3ca46d7257]
cannot compute difference between binary files
Added www/CollRev2.gif version [581afba0a0]
cannot compute difference between binary files
Added www/CollRev3.gif version [996e26f2d6]
cannot compute difference between binary files
Added www/CollRev4.gif version [2344026a4c]
cannot compute difference between binary files