@@ -52,6 +52,105 @@ public function parseLogRevisions(SimpleXMLElement $xml)
5252 return $ revisions ;
5353 }
5454
55+ /**
56+ * Parse log entries from given XML document
57+ *
58+ * @param SimpleXMLElement $xml
59+ * @throws \UnexpectedValueException
60+ * @return array
61+ * @link https://gforge.inria.fr/scm/viewvc/viewvc.org/template-authoring-guide.html#variables-log
62+ */
63+ public function parseLogEntries (SimpleXMLElement $ xml )
64+ {
65+ $ entries = array ();
66+
67+ foreach ($ xml ->xpath ('//div[pre] ' ) as $ div ) {
68+ /* @var $div SimpleXMLElement */
69+
70+ // skip "(vendor branch)" "em" tag if found
71+ $ off = ((string )$ div ->em [0 ] === '(vendor branch) ' ) ? 1 : 0 ;
72+
73+ $ entry = array (
74+ // revision is first "strong" element (subversion wraps this in "a" element)
75+ 'revision ' => (string )$ this ->first ($ div ->xpath ('.//strong[1] ' )),
76+ // date is in first "em" element
77+ 'date ' => new \DateTime ((string )$ div ->em [0 + $ off ]),
78+ // author is in second "em" element
79+ 'author ' => (string )$ div ->em [1 + $ off ],
80+ // message is in only "pre" element
81+ 'message ' => (string )$ div ->pre
82+ );
83+
84+ // ease parsing each line by splitting on "br" element, skip static rows for revision/date
85+ $ parts = explode ('<br /> ' , substr ($ div ->asXML (), 5 , -6 ));
86+ unset($ parts [0 ], $ parts [1 ]);
87+
88+ foreach ($ parts as $ part ) {
89+ $ part = new SimpleXMLElement ('<body> ' . $ part . '</body> ' );
90+ $ str = (string )$ part ;
91+
92+ if (substr ($ str , 0 , 7 ) === 'Diff to ' ) {
93+ $ value = array ();
94+
95+ foreach ($ part ->xpath ('.//a ' ) as $ a ) {
96+ $ text = (string )$ a ;
97+ $ pos = strrpos ($ text , ' ' );
98+
99+ // text should be "previous X.Y", otherwise ignore "(colored)" with no blank
100+ if ($ pos !== false ) {
101+ $ value [substr ($ text , 0 , $ pos )] = substr ($ text , $ pos + 1 );
102+ }
103+ }
104+
105+ $ entry ['diff ' ] = $ value ;
106+ } elseif (substr ($ str , 0 , 7 ) === 'Branch: ' || substr ($ str , 0 , 9 ) === 'CVS Tags: ' || substr ($ str , 0 , 17 ) === 'Branch point for: ' ) {
107+ $ value = array ();
108+
109+ foreach ($ part ->xpath ('.//a/strong ' ) as $ a ) {
110+ $ value []= (string )$ a ;
111+ }
112+
113+ $ key = $ str [0 ] === 'B ' ? ($ str [6 ] === ': ' ? 'branches ' : 'branchpoints ' ) : 'tags ' ;
114+ $ entry [$ key ] = $ value ;
115+ } elseif (substr ($ str , 0 , 13 ) === 'Changes since ' ) {
116+ // "strong" element contains "X.Y: +1 -2 lines"
117+ $ value = (string )$ part ->strong ;
118+ $ pos = strpos ($ value , ': ' );
119+
120+ // previous revision is before colon
121+ $ entry ['previous ' ] = substr ($ value , 0 , $ pos );
122+
123+ // changes are behind colon
124+ $ entry ['changes ' ] = substr ($ value , $ pos + 2 );
125+ } elseif (substr ($ str , 0 , 14 ) === 'Original Path: ' ) {
126+ $ entry ['original ' ] = (string )$ part ->a ->em ;
127+ } elseif (substr ($ str , 0 , 12 ) === 'File length: ' ) {
128+ $ entry ['size ' ] = (int )substr ($ str , 13 );
129+ } elseif (isset ($ part ->strong ->em ) && (string )$ part ->strong ->em === 'FILE REMOVED ' ) {
130+ $ entry ['deleted ' ] = true ;
131+ }
132+ }
133+
134+ // previous is either set via "changes since" or link to "diff to" previous
135+ if (isset ($ entry ['diff ' ]['previous ' ])) {
136+ $ entry ['previous ' ] = $ entry ['diff ' ]['previous ' ];
137+ }
138+
139+ if ($ off ) {
140+ $ entry ['vendor ' ] = true ;
141+ }
142+
143+ $ entries []= $ entry ;
144+ }
145+
146+ return $ entries ;
147+ }
148+
149+ private function first (array $ a )
150+ {
151+ return $ a [0 ];
152+ }
153+
55154 private function linkParameters ($ href )
56155 {
57156 $ args = array ();
0 commit comments