1 //
2 // aegis - project change supervisor
3 // Copyright (C) 2001, 2003-2008 Peter Miller
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see
17 // <http://www.gnu.org/licenses/>.
18 //
19
20 #include <aeimport/format/private.h>
21 #include <aeimport/format/rcs.h>
22 #include <aeimport/format/rcs/gram.h>
23 #include <aeimport/format/version.h>
24 #include <common/str_list.h>
25 #include <libaegis/os.h>
26
27
28 static void
destructor(format_ty *)29 destructor(format_ty *)
30 {
31 }
32
33
34 static int
is_a_candidate(format_ty *,string_ty * filename)35 is_a_candidate(format_ty *, string_ty *filename)
36 {
37 return
38 (
39 filename->str_length > 2
40 &&
41 filename->str_text[filename->str_length - 2] == ','
42 &&
43 filename->str_text[filename->str_length - 1] == 'v'
44 );
45 }
46
47
48 static string_ty *
sanitize(format_ty *,string_ty * filename,int last_part)49 sanitize(format_ty *, string_ty *filename, int last_part)
50 {
51 static string_ty *rcs = 0;
52 static string_ty *cvs = 0;
53 static string_ty *attic = 0;
54
55 if (!rcs)
56 {
57 rcs = str_from_c("RCS");
58 cvs = str_from_c("CVS");
59 attic = str_from_c("Attic");
60 }
61
62 //
63 // Break the filename into path elements.
64 //
65 string_list_ty sl;
66 sl.split(filename, "/");
67
68 //
69 // Get rid of path elements named "RCS" or "CVS" or "Attic".
70 //
71 string_list_ty sl2;
72 for (size_t j = 0; j < sl.nstrings; ++j)
73 {
74 string_ty *s;
75
76 s = sl.string[j];
77 if (!str_equal(s, rcs) && !str_equal(s, cvs) && !str_equal(s, attic))
78 sl2.push_back(s);
79 }
80
81 if (last_part)
82 {
83 //
84 // Remove the ",v" from the end of the last path element.
85 //
86 if (sl2.nstrings)
87 {
88 string_ty *s;
89
90 s = sl2.string[sl2.nstrings - 1];
91 if
92 (
93 s->str_length >= 2
94 &&
95 s->str_text[s->str_length - 2] == ','
96 &&
97 s->str_text[s->str_length - 1] == 'v'
98 )
99 {
100 sl2.string[sl2.nstrings - 1] =
101 str_n_from_c(s->str_text, s->str_length - 2);
102 str_free(s);
103 }
104 }
105 }
106
107 //
108 // Rebuild the filename from the remaining path elements.
109 //
110 return sl2.unsplit("/");
111 }
112
113
114 static format_version_ty *
read_versions(format_ty *,string_ty * physical,string_ty * logical)115 read_versions(format_ty *, string_ty *physical, string_ty *logical)
116 {
117 return rcs_parse(physical, logical);
118 }
119
120
121 static string_ty *
history_put(format_ty *)122 history_put(format_ty *)
123 {
124 return
125 str_from_c
126 (
127 "ci -u -d -M -m${quote ($version) ${change description}} "
128 "-t/dev/null ${quote $input} ${quote $history,v}; "
129 "rcs -U ${quote $history,v}"
130 );
131 }
132
133
134 static string_ty *
history_get(format_ty *)135 history_get(format_ty *)
136 {
137 return
138 str_from_c
139 (
140 "co -r${quote $edit} -p ${quote $history,v} > ${quote $output}"
141 );
142 }
143
144
145 static string_ty *
history_query(format_ty *)146 history_query(format_ty *)
147 {
148 return
149 str_from_c
150 (
151 "rlog -r ${quote $history,v} | awk '/^revision/ {print $$2}'"
152 );
153 }
154
155
156 static string_ty *
diff(format_ty *)157 diff(format_ty *)
158 {
159 //
160 // I'd prefer to say "diff -U10", but we can't rely on GNU
161 // Diff being installed everywhere. It's a risk even using
162 // a context diff, because not all non-GNU diff progs have -c.
163 //
164 return
165 str_from_c
166 (
167 "set +e; "
168 CONF_DIFF " "
169 #ifdef HAVE_GNU_DIFF
170 "-U10 --text "
171 #else
172 "-c "
173 #endif
174 "${quote $original} ${quote $input} > ${quote $output}; "
175 "test $? -le 1"
176 );
177 }
178
179
180 static string_ty *
merge(format_ty *)181 merge(format_ty *)
182 {
183 return
184 str_from_c
185 (
186 "set +e; "
187 "merge -p -L baseline -L C$c ${quote $mostrecent} "
188 "${quote $original} ${quote $input} > ${quote $output}; "
189 "test $? -le 1"
190 );
191 }
192
193
194 static void
unlock(format_ty *,string_ty * filename)195 unlock(format_ty *, string_ty *filename)
196 {
197 int flags;
198 string_ty *cmd;
199 string_ty *qfn;
200
201 //
202 // -b means resume working from the trunk, not a branch
203 // -e means get rid of any access list
204 // -ko means no keyword expansion
205 // -M means do not send mail
206 // -q means operate quietly
207 // -U means set locking to non-strict
208 //
209 // There doesn't seem to be an option to get rid of all locks.
210 //
211 qfn = str_quote_shell(filename);
212 cmd = str_format("rcs -b -e -M -q -U %s", qfn->str_text);
213 str_free(qfn);
214 flags = OS_EXEC_FLAG_ERROK;
215 os_execute(cmd, flags, os_curdir());
216 str_free(cmd);
217 }
218
219
220 static format_vtable_ty vtbl =
221 {
222 sizeof(format_ty),
223 destructor,
224 is_a_candidate,
225 sanitize,
226 read_versions,
227 history_put,
228 history_get,
229 history_query,
230 diff,
231 merge,
232 unlock,
233 };
234
235
236 format_ty *
format_rcs_new()237 format_rcs_new()
238 {
239 return format_new(&vtbl);
240 }
241