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