1 /*****************************************************************************\
3 * Name : vsts_version_fixer *
4 * Author : Chris Koeritz *
6 *******************************************************************************
7 * Copyright (c) 2008-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
15 #include <application/application_shell.h>
16 #include <application/command_line.h>
17 #include <application/hoople_main.h>
18 #include <application/windoze_helper.h>
19 #include <basis/astring.h>
20 #include <basis/environment.h>
21 #include <basis/functions.h>
22 #include <filesystem/byte_filer.h>
23 #include <filesystem/directory.h>
24 #include <filesystem/filename.h>
25 #include <processes/launch_process.h>
26 #include <structures/static_memory_gremlin.h>
27 #include <structures/string_array.h>
28 #include <timely/time_stamp.h>
29 #include <versions/version_ini.h>
32 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
34 #define BASE_LOG(s) program_wide_logger::get().log(s, ALWAYS_PRINT)
36 using namespace application;
37 //using namespace basis;
38 using namespace filesystem;
39 using namespace loggers;
40 using namespace processes;
41 using namespace structures;
42 using namespace timely;
43 using namespace versions;
45 //#define DEBUG_VSTS_VERSION_FIXER
46 // uncomment for noisy version.
48 ////////////////////////////////////////////////////////////////////////////
50 class vsts_version_fixer : public application::application_shell
53 vsts_version_fixer() : application_shell() {}
54 virtual ~vsts_version_fixer() {}
56 virtual int execute();
58 DEFINE_CLASS_NAME("vsts_version_fixer");
60 void remove_confusing_files();
61 //!< tosses out the generated files that confuse ms devstudio.
64 typedef bool spider_method(const directory ¤t);
65 //!< prototype for functions that are called during directory spidering.
66 /*!< this function should do whatever work is needed on the items in
67 that "current" directory. true should be returned by this method when
68 the traversal of the directory is still desired. if there is a reason
69 to stop traversing the directory hierarchy, then it should return false. */
71 //hmmm: support postfix and in order also.
72 //hmmm: support reporting where the spidering stopped.
73 bool spider_directory(directory start, spider_method to_invoke);
74 //!< traverses hierarchy "start" in prefix order while calling "to_invoke".
75 /*!< true is returned if all invoked spider methods returned true.
76 otherwise, false is returned. */
79 bool perform_version_stamping(const filename &start_name);
80 //!< finds all version ini files and applies stamps using them.
82 void whack_in_subdirs(const directory &start,
83 const string_array &file_whacks, const string_array &dir_whacks);
84 //!< recursively cleans all items found in "file_whacks" and "dir_whacks".
85 /*!< "file_whacks" is a list of file suffixes to whack. for example, to
86 remove all files matching a pattern *.exe, pass in just ".exe" in the
87 "file_whacks". the "dir_whacks" list is a list of directories to
88 completely obliterate where found. */
91 HOOPLE_MAIN(vsts_version_fixer, )
93 ////////////////////////////////////////////////////////////////////////////
95 //hmmm: move to a useful place; maybe even in directory class?
96 bool vsts_version_fixer::spider_directory(directory start,
97 spider_method to_invoke)
99 FUNCDEF("spider_directory");
101 using namespace basis;
103 //LOG(astring("spider_directory: ") + start.path());
104 // call our method on this directory first. this ensures that we have
105 // dealt with it before we spider off elsewhere.
106 bool ret = to_invoke(start);
107 if (!ret) return false; // bail.
109 // now let's look at the subdirectories. we'll recurse on all of them in
111 const string_array &dirs = start.directories();
112 //LOG(astring("dirs found to spider: ") + dirs.text_form());
113 for (int dir_indy = 0; dir_indy < dirs.length(); dir_indy++) {
114 const astring ¤t_dir = dirs[dir_indy];
115 //LOG(astring("currdir into ") + current_dir);
116 if (current_dir.equal_to(".svn")) continue; // skip this.
117 if (current_dir.equal_to("CVS")) continue; // skip this also.
118 directory new_dir(start.path() + "/" + current_dir, start.pattern().observe());
119 bool ret = spider_directory(new_dir, to_invoke);
120 if (!ret) return false; // bail from subdir issue.
122 // if we made it to here, everything was groovy.
126 ////////////////////////////////////////////////////////////////////////////
128 #define static_class_name() "vsts_version_fixer"
130 // global variables used to communicate with whacking_spider.
131 string_array global_file_whacks;
132 string_array global_dir_whacks;
134 bool whacking_spider(const directory ¤t)
136 FUNCDEF("whacking_spider");
137 using namespace basis;
138 //LOG(astring("whacking_spider: ") + current.path());
139 // iterate across the files in the directory and check for evil ones.
140 const string_array &files = current.files();
141 for (int file_indy = 0; file_indy < files.length(); file_indy++) {
142 const astring ¤t_file = files[file_indy];
143 //LOG(astring("currfile ") + current_file);
144 // now iterate across our pattern list to see if this thing is
145 // one of the offending files.
146 for (int pat_indy = 0; pat_indy < global_file_whacks.length(); pat_indy++) {
147 //LOG(astring("currpat ") + global_file_whacks[pat_indy]);
148 if (current_file.iends(global_file_whacks[pat_indy])) {
149 filename goner(current.path() + "/" + current_file);
150 BASE_LOG(astring("whack file: ") + goner.raw());
152 break; // stop looking at the pattern list for matches.
157 // okay, now that we've cleaned out those files, let's look at the
159 const string_array &dirs = current.directories();
160 for (int dir_indy = 0; dir_indy < dirs.length(); dir_indy++) {
161 const astring ¤t_dir = dirs[dir_indy];
162 //LOG(astring("currdir ") + current_dir);
163 for (int pat_indy = 0; pat_indy < global_dir_whacks.length(); pat_indy++) {
164 if (current_dir.iequals(global_dir_whacks[pat_indy])) {
165 filename goner(current.path() + "/" + current_dir);
166 BASE_LOG(astring("whack dir: ") + goner.raw());
167 //hmmm: plug in recursive delete here instead.
169 launch_process::run("rm", astring("-rf ") + goner.raw(), launch_process::AWAIT_APP_EXIT, kid);
170 break; // skip remainder of patterns for this dir.
177 #undef static_class_name
179 ////////////////////////////////////////////////////////////////////////////
181 void vsts_version_fixer::whack_in_subdirs(const directory &start,
182 const string_array &file_whacks, const string_array &dir_whacks)
184 FUNCDEF("whack_in_subdirs");
185 using namespace basis;
187 // save the lists so the spider method can see them.
188 // note that this approach with a global variable would be bad if there
189 // were concurrent invocations of the spidering, but we're not doing
191 global_file_whacks = file_whacks;
192 global_dir_whacks = dir_whacks;
194 bool worked = spider_directory(start, whacking_spider);
196 LOG(astring("spidering of ") + start.path() + " failed for some reason.");
200 ////////////////////////////////////////////////////////////////////////////
202 #define static_class_name() "vsts_version_fixer"
204 basis::astring global_build_ini;
206 bool stamping_spider(const directory ¤t)
208 FUNCDEF("stamping_spider");
209 using namespace basis;
210 //LOG(astring("stamping_spider: ") + current.path());
212 const string_array &files = current.files();
213 for (int file_indy = 0; file_indy < files.length(); file_indy++) {
214 const astring ¤t_file = files[file_indy];
215 //LOG(astring("currfile ") + current_file);
216 // we won't process the "core_version.ini" file, which is a special
217 // case that is somewhat well known as not being a file used (by us)
219 if (current_file.ends("version.ini")
220 && !current_file.iequals("core_version.ini") ) {
221 //LOG(astring("found ver file: ") + current.path() + "/" + current_file);
222 version_ini::one_stop_version_stamp(current.path() + "/" + current_file,
223 global_build_ini, true);
229 #undef static_class_name
231 ////////////////////////////////////////////////////////////////////////////
233 bool vsts_version_fixer::perform_version_stamping(const filename &start_name)
235 FUNCDEF("perform_version_stamping");
236 directory start(start_name);
237 return spider_directory(start, stamping_spider);
240 ////////////////////////////////////////////////////////////////////////////
242 void vsts_version_fixer::remove_confusing_files()
244 using namespace basis;
245 // clean out a few directories that show up in the source tree from c#
246 // projects compilation. c# projects always rebuild every time anyways,
247 // so this doesn't lose us any compilation time. the only thing c#
248 // projects don't ever seem to rebuild is their version resource, unless
249 // they're forced to totally recompile like we cause below.
250 string_array source_file_whacks; // none right now.
251 string_array source_dir_whacks;
252 source_dir_whacks += "obj";
253 source_dir_whacks += "Debug";
254 source_dir_whacks += "Release";
255 source_dir_whacks += "bin";
256 source_dir_whacks += "temp_build";
257 directory repo_source(environment::get("FEISTY_MEOW_DIR") + "/source");
258 whack_in_subdirs(repo_source, source_file_whacks, source_dir_whacks);
259 directory libra_src(environment::get("FEISTY_MEOW_DIR") + "/libraries");
260 whack_in_subdirs(libra_src, source_file_whacks, source_dir_whacks);
261 directory produ_src(environment::get("FEISTY_MEOW_DIR") + "/products");
262 whack_in_subdirs(produ_src, source_file_whacks, source_dir_whacks);
264 /* this never helped.
265 // clean out a variety of bad files in the objects hierarchy.
266 // currently this is just the generated RES files which we have seen cause
267 // vsts to think apps and dlls are up to date when they are actually not.
268 directory repo_objects(environment::get("FEISTY_MEOW_DIR"));
269 string_array objects_file_whacks;
270 objects_file_whacks += ".res";
271 string_array objects_dir_whacks; // none right now.
272 whack_in_subdirs(repo_objects, objects_file_whacks, objects_dir_whacks);
276 int vsts_version_fixer::execute()
279 using namespace basis;
280 log(time_stamp::notarize(true) + "vsts_version_fixer started.", ALWAYS_PRINT);
282 remove_confusing_files();
284 astring repo_dir = environment::get("FEISTY_MEOW_DIR");
286 // figure out which build parameter file to use.
287 global_build_ini = "";
288 astring parmfile = environment::get("BUILD_PARAMETER_FILE");
290 global_build_ini = parmfile;
291 LOG(astring("found parm variable ") + parmfile);
293 // they didn't specify the file. argh.
294 global_build_ini = repo_dir + "/production/feisty_meow_config.ini";
295 if (!filename(global_build_ini).exists()) {
296 LOG(astring("guess not found: ") + global_build_ini);
297 LOG("cannot locate the build configuration file.");
302 // now stamp versions on everything we can find.
303 filename repo_source = repo_dir + "/../../libraries";
304 if (!repo_source.exists()) {
305 repo_source = repo_dir + "/source";
306 if (!repo_source.exists()) {
307 LOG("cannot locate the main library source location.");
311 LOG(astring("chose source dir as ") + repo_source);
312 perform_version_stamping(repo_source);
314 filename repo_apps = repo_dir + "/../../products";
315 if (repo_apps.exists()) {
316 perform_version_stamping(repo_apps);
318 log(time_stamp::notarize(true) + "vsts_version_fixer finished.", ALWAYS_PRINT);
322 #ifdef __BUILD_STATIC_APPLICATION__
323 // static dependencies found by buildor_gen_deps.sh:
324 #include <application/application_shell.cpp>
325 #include <application/command_line.cpp>
326 #include <application/windoze_helper.cpp>
327 #include <basis/astring.cpp>
328 #include <basis/common_outcomes.cpp>
329 #include <basis/environment.cpp>
330 #include <basis/guards.cpp>
331 #include <basis/mutex.cpp>
332 #include <basis/utf_conversion.cpp>
333 #include <configuration/application_configuration.cpp>
334 #include <configuration/configurator.cpp>
335 #include <configuration/ini_configurator.cpp>
336 #include <configuration/ini_parser.cpp>
337 #include <configuration/table_configurator.cpp>
338 #include <configuration/variable_tokenizer.cpp>
339 #include <filesystem/byte_filer.cpp>
340 #include <filesystem/directory.cpp>
341 #include <filesystem/filename.cpp>
342 #include <loggers/combo_logger.cpp>
343 #include <loggers/console_logger.cpp>
344 #include <loggers/critical_events.cpp>
345 #include <loggers/file_logger.cpp>
346 #include <loggers/program_wide_logger.cpp>
347 #include <processes/launch_process.cpp>
348 #include <structures/bit_vector.cpp>
349 #include <structures/checksums.cpp>
350 #include <structures/object_packers.cpp>
351 #include <structures/static_memory_gremlin.cpp>
352 #include <structures/string_hasher.cpp>
353 #include <structures/string_table.cpp>
354 #include <structures/version_record.cpp>
355 #include <textual/byte_formatter.cpp>
356 #include <textual/parser_bits.cpp>
357 #include <textual/string_manipulation.cpp>
358 #include <timely/earth_time.cpp>
359 #include <timely/time_control.cpp>
360 #include <timely/time_stamp.cpp>
361 #include <versions/version_ini.cpp>
362 #endif // __BUILD_STATIC_APPLICATION__