1 /* === S Y N F I G ========================================================= */
2 /*! \file cvs.cpp
3 ** \brief Template File
4 **
5 ** $Id$
6 **
7 ** \legal
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 ** This package is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU General Public License as
12 ** published by the Free Software Foundation; either version 2 of
13 ** the License, or (at your option) any later version.
14 **
15 ** This package is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ** General Public License for more details.
19 ** \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 # include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31
32 #include <synfig/general.h>
33
34 #include "cvs.h"
35 #include <ETL/stringf>
36 #include <fstream>
37 #include <iostream>
38 #include <cstdlib>
39
40
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 //#include <unistd.h>
44
45 #include <cassert>
46
47 #include <synfigapp/localization.h>
48
49 #endif
50
51 /* === U S I N G =========================================================== */
52
53 using namespace std;
54 using namespace etl;
55 using namespace synfig;
56 using namespace synfigapp;
57
58 /* === M A C R O S ========================================================= */
59
60 #define cvs_command synfig::String("cvs -z4")
61
62 #ifndef _WIN32
63 #define HAVE_STRPTIME
64 #endif
65
66 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
_daylight_()67 time_t _daylight_() { time_t t(time(0)); return localtime(&t)->tm_gmtoff; }
68 #define daylight _daylight_()
69 #endif
70
71 /* === G L O B A L S ======================================================= */
72
73 /* === P R O C E D U R E S ================================================= */
74
75 /* === M E T H O D S ======================================================= */
76
CVSInfo(const synfig::String & file_name)77 CVSInfo::CVSInfo(const synfig::String& file_name)
78 {
79 update_available_=false;
80 set_file_name(file_name);
81 }
82
CVSInfo()83 CVSInfo::CVSInfo():
84 in_sandbox_(),
85 in_repository_(),
86 update_available_(false),
87 original_timestamp_()
88 { }
89
~CVSInfo()90 CVSInfo::~CVSInfo()
91 {
92 }
93
94 void
set_file_name(const synfig::String & file_name)95 CVSInfo::set_file_name(const synfig::String& file_name)
96 {
97 file_name_=file_name;
98
99 std::ifstream file((dirname(file_name_)+"/CVS/Root").c_str());
100
101 if(file)
102 {
103 in_sandbox_=true;
104 calc_repository_info();
105 }
106 else
107 in_sandbox_=false;
108 }
109
110 void
calc_repository_info()111 CVSInfo::calc_repository_info()
112 {
113 #ifdef _DEBUG
114 synfig::info("in_sandbox() = %d",in_sandbox());
115 #endif
116
117 if(!in_sandbox_)
118 return;
119
120 std::ifstream file((dirname(file_name_)+"/CVS/Entries").c_str());
121
122 while(file)
123 {
124 String line;
125 getline(file,line);
126 if(line.find(basename(file_name_))!=String::npos)
127 {
128 in_repository_=true;
129 String::size_type s,f;
130
131 // Grab the version
132 s=line.find('/',1);
133 assert(s!=String::npos);
134 s++;
135 f=line.find('/',s+1);
136 assert(f!=String::npos);
137 cvs_version_=String(line,s,f-s);
138
139 // Grab the time
140 #ifdef HAVE_STRPTIME
141 s=f+1;
142 f=line.find('/',s+1);
143 assert(f!=String::npos);
144 tm time_struct;
145 strptime(String(line,s,f-s).c_str(),"%c",&time_struct);
146 original_timestamp_=mktime(&time_struct);
147 #endif
148
149 if(
150 system(strprintf(
151 "cd '%s' && cvs status '%s' | grep -q -e 'Needs Patch'",
152 dirname(file_name_).c_str(),
153 basename(file_name_).c_str()
154 ).c_str())==0
155 )
156 {
157 synfig::info("UPDATE_AVAILABLE=TRUE");
158 update_available_=true;
159 }
160 else
161 {
162 system(strprintf(
163 "cd '%s' && cvs status '%s'",
164 dirname(file_name_).c_str(),
165 basename(file_name_).c_str()
166 ).c_str());
167 synfig::info("UPDATE_AVAILABLE=FALSE");
168 update_available_=false;
169 }
170
171
172 #ifdef _DEBUG
173 synfig::info("in_repository() = %d",in_repository());
174 synfig::info("get_cvs_version() = %s",get_cvs_version().c_str());
175 synfig::info("get_original_timestamp() = %s",ctime(&get_original_timestamp()));
176 time_t t(get_current_timestamp());
177 synfig::info("get_current_timestamp() = %s",ctime(&t));
178 synfig::info("get_cvs_root() = %s",get_cvs_root().c_str());
179 synfig::info("get_cvs_module() = %s",get_cvs_module().c_str());
180 #endif
181 return;
182 }
183 }
184
185 in_repository_=false;
186 cvs_version_.clear();
187 original_timestamp_=0;
188
189 #ifdef _DEBUG
190 synfig::info("in_repository() = %d",in_repository());
191 #endif
192 }
193
194 bool
in_sandbox() const195 CVSInfo::in_sandbox()const
196 {
197 return in_sandbox_;
198 }
199
200 bool
in_repository() const201 CVSInfo::in_repository()const
202 {
203 if(!in_sandbox_)
204 return false;
205 return in_repository_;
206 }
207
208 bool
is_modified() const209 CVSInfo::is_modified()const
210 {
211 if(!in_sandbox() || !in_repository())
212 return false;
213 #ifdef _DEBUG
214 synfig::info("%d-%d=%d",get_current_timestamp(),get_original_timestamp(),get_current_timestamp()-get_original_timestamp());
215 #endif
216 return get_current_timestamp()!=get_original_timestamp() && abs(get_current_timestamp()-get_original_timestamp())!=3600;
217 }
218
219 bool
is_updated() const220 CVSInfo::is_updated()const
221 {
222 return update_available_;
223 }
224
225 const synfig::String&
get_cvs_version() const226 CVSInfo::get_cvs_version()const
227 {
228 return cvs_version_;
229 }
230
231 const time_t&
get_original_timestamp() const232 CVSInfo::get_original_timestamp()const
233 {
234 return original_timestamp_;
235 }
236
237 time_t
get_current_timestamp() const238 CVSInfo::get_current_timestamp()const
239 {
240 struct stat st;
241 if(stat(file_name_.c_str(),&st)<0)
242 {
243 synfig::error("Unable to get file stats");
244 return false;
245 }
246 time_t ret((daylight-1)*3600);
247 //ret+=timezone;
248 ret+=st.st_mtime;
249 return ret;
250 }
251
252 synfig::String
get_cvs_root() const253 CVSInfo::get_cvs_root()const
254 {
255 if(!in_sandbox_)
256 return synfig::String();
257
258 std::ifstream file((dirname(file_name_)+"/CVS/Root").c_str());
259
260 if(file)
261 {
262 String ret;
263 getline(file,ret);
264 return ret;
265 }
266
267 return synfig::String();
268 }
269
270 synfig::String
get_cvs_module() const271 CVSInfo::get_cvs_module()const
272 {
273 if(!in_sandbox_)
274 return synfig::String();
275
276 std::ifstream file((dirname(file_name_)+"/CVS/Repository").c_str());
277
278 if(file)
279 {
280 String ret;
281 getline(file,ret);
282 return ret;
283 }
284
285 return synfig::String();
286 }
287
288 // This function pre-processes the message so that we
289 // don't get any CVS syntax errors.
fix_msg(const synfig::String & message)290 inline synfig::String fix_msg(const synfig::String& message)
291 {
292 synfig::String ret;
293 int i;
294 for(i=0;i<(int)message.size();i++)
295 {
296 if(message[i]=='\'')
297 ret+="'\"'\"'";
298 else
299 ret+=message[i];
300 }
301 return ret;
302 }
303
304 void
cvs_add(const synfig::String & message)305 CVSInfo::cvs_add(const synfig::String& message)
306 {
307 if(!in_sandbox_)
308 {
309 synfig::error("cvs_add(): Not in a sand box");
310 throw int();
311 return;
312 }
313
314 synfig::String command(strprintf("cd '%s' && %s add -m '%s' '%s'",dirname(file_name_).c_str(),cvs_command.c_str(),fix_msg(message).c_str(),basename(file_name_).c_str()));
315
316 int ret(system(command.c_str()));
317
318 calc_repository_info();
319
320 switch(ret)
321 {
322 case 0:
323 break;
324 default:
325 synfig::error("Unknown errorcode %d (\"%s\")",ret,command.c_str());
326 throw(ret);
327 break;
328 }
329 }
330
331 void
cvs_update()332 CVSInfo::cvs_update()
333 {
334 if(!in_sandbox_)
335 {
336 synfig::error("cvs_update(): Not in a sand box");
337 throw int();
338 return;
339 }
340
341 synfig::String command(strprintf("cd '%s' && %s update '%s'",dirname(file_name_).c_str(),cvs_command.c_str(),basename(file_name_).c_str()));
342
343 int ret(system(command.c_str()));
344
345 calc_repository_info();
346
347 switch(ret)
348 {
349 case 0:
350 break;
351 default:
352 synfig::error("Unknown errorcode %d (\"%s\")",ret,command.c_str());
353 throw(ret);
354 break;
355 }
356 }
357
358 void
cvs_commit(const synfig::String & message)359 CVSInfo::cvs_commit(const synfig::String& message)
360 {
361 if(!in_sandbox_)
362 {
363 synfig::error("cvs_commit(): Not in a sand box");
364 throw int();
365 return;
366 }
367
368 synfig::String command(strprintf("cd '%s' && %s commit -m '%s' '%s'",dirname(file_name_).c_str(),cvs_command.c_str(),fix_msg(message).c_str(),basename(file_name_).c_str()));
369
370 int ret(system(command.c_str()));
371
372 calc_repository_info();
373
374 switch(ret)
375 {
376 case 0:
377 break;
378 default:
379 synfig::error("Unknown errorcode %d (\"%s\")",ret,command.c_str());
380 if(is_modified())
381 throw(ret);
382 break;
383 }
384 }
385