1 //####COPYRIGHTBEGIN####
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 2003 Bart Veer
5 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
7 // This program is part of the eCos host tools.
9 // This program is free software; you can redistribute it and/or modify it
10 // under the terms of the GNU General Public License as published by the Free
11 // Software Foundation; either version 2 of the License, or (at your option)
14 // This program is distributed in the hope that it will be useful, but WITHOUT
15 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 // You should have received a copy of the GNU General Public License along with
20 // this program; if not, write to the Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 // ----------------------------------------------------------------------------
25 //####COPYRIGHTEND####
26 //==========================================================================
30 // The implementation of ecosconfig command line processing
32 //==========================================================================
33 //==========================================================================
34 //#####DESCRIPTIONBEGIN####
39 //####DESCRIPTIONEND####
40 //==========================================================================
42 #include <sys/param.h>
43 #include <unistd.h> /* for realpath() */
48 #include <sys/cygwin.h> /* for cygwin_conv_to_win32_path() */
50 #include "cdl_exec.hxx"
51 #include "ecosconfig.hxx"
53 #define TOOL_VERSION "2.0b1"
54 #define TOOL_COPYRIGHT "Copyright (c) 2002 Red Hat, Inc."
55 #define DEFAULT_SAVE_FILE "ecos.ecc"
56 static char* tool = "ecosconfig";
58 // When running under cygwin there may be confusion between cygwin and
59 // Windows paths. Some paths will be passed on to the Tcl library,
60 // which sometimes will accept a cygwin path and sometimes not. This
61 // does not affect the VC++ build which only accepts Windows paths,
62 // and obviously it does not affect any Unix platfom.
65 translate_path(std::string& path)
68 char buffer [MAXPATHLEN + 1];
72 cygwin_conv_to_win32_path (path.c_str (), buffer);
73 result = std::string(buffer);
77 # define TRANSLATE_PATH(a) translate_path(a)
79 # define TRANSLATE_PATH(a) (a)
82 int main (int argc, char * argv []) {
84 // process command qualifiers
85 std::string repository; // --srcdir=
86 std::string savefile; // --config=
87 std::string install_prefix; // --prefix=
88 bool version = false; // --version
89 bool no_resolve = false; // --no-resolve
90 bool quiet = false; // -q, --quiet
91 bool verbose = false; // -v, --verbose
92 bool ignore_errors = false; // -i, --ignore-errors
93 bool no_updates = false; // -n, --no-updates,
94 bool help = false; // --help
95 bool enable_debug_set = false; // --enable-debug or --disable-debug
96 int debug_level = 0; // --enable-debug=[0|1|2]
98 Tcl_FindExecutable(argv[0]);
100 // getopt() cannot easily be used here since this code has to
101 // build with VC++ as well.
104 for (command_index = 1; command_index < argc; command_index++) { // for each command line argument
105 char* arg = argv[command_index];
106 if (0 == strcmp(arg, "--help")) {
108 } else if ((0 == strcmp(arg, "-q")) || (0 == strcmp(arg, "--quiet"))) {
109 // Allow repeated use of -q and -v to override each other.
110 // This is useful in conjunction with shell aliases.
113 } else if ((0 == strcmp(arg, "-v")) || (0 == strcmp(arg, "--verbose"))) {
116 } else if ((0 == strcmp(arg, "-i")) || (0 == strcmp(arg, "--ignore-errors"))) {
117 // Duplicate use of -i and the other flags is harmless.
118 ignore_errors = true;
119 } else if ((0 == strcmp(arg, "-n")) || (0 == strcmp(arg, "--no-updates"))) {
121 } else if (0 == strcmp(arg, "--version")) {
123 } else if (0 == strcmp(arg, "--no-resolve")) {
125 } else if (0 == strcmp(arg, "--enable-debug")) {
126 enable_debug_set = true;
128 } else if (0 == strcmp(arg, "--disable-debug")) {
129 enable_debug_set = true;
131 } else if (0 == strncmp(arg, "--srcdir", 8)) {
132 // Duplicate use of --srcdir and other data-containing options should
133 // be marked as an error.
134 if ("" != repository) {
135 fprintf(stderr, "%s: the `--srcdir' option should be used only once.\n", tool);
139 repository = std::string(arg + 9);
140 if ("" == repository) {
141 fprintf(stderr, "%s: missing component repository after `--srcdir='\n", tool);
144 } else if ('\0' == arg[8]) {
146 if (command_index == argc) {
147 fprintf(stderr, "%s: missing component repository after `--srcdir'\n", tool);
150 repository = argv[command_index];
153 fprintf(stderr, "%s: invalid option `%s'\n", tool, arg);
157 } else if (0 == strncmp(arg, "--config", 8)) {
158 if ("" != savefile) {
159 fprintf(stderr, "%s: the `--config' option should be used only once.\n", tool);
163 savefile = std::string(arg + 9);
164 if ("" == savefile) {
165 fprintf(stderr, "%s: missing configuration savefile after `--config='\n", tool);
168 } else if ('\0' == arg[8]) {
170 if (command_index == argc) {
171 fprintf(stderr, "%s: missing configuration savefile after `--config'\n", tool);
174 savefile = argv[command_index];
177 fprintf(stderr, "%s: invalid option `%s'\n", tool, arg);
181 } else if (0 == strncmp(arg, "--prefix", 8)) {
182 if ("" != install_prefix) {
183 fprintf(stderr, "%s: the `--prefix' option should be used only once.\n", tool);
187 install_prefix = std::string(arg + 9);
188 if ("" == install_prefix) {
189 fprintf(stderr, "%s: missing install prefix after `--prefix='\n", tool);
192 } else if ('\0' == arg[8]) {
194 if (command_index == argc) {
195 fprintf(stderr, "%s: missing install prefix after `--prefix'\n", tool);
198 install_prefix = argv[command_index];
201 fprintf(stderr, "%s: invalid option `%s'\n", tool, arg);
206 // The argument is not a qualifier
207 // However, none of the sub-commands begin with a -
209 fprintf(stderr, "%s: unknown option `%s'\n", tool, arg);
212 break; // end of qualifiers
217 printf("args_ok is %d\n", args_ok);
218 printf("help is %d\n", help);
219 printf("version is %d\n", version);
220 printf("no_resolve is %d\n", no_resolve);
221 printf("quiet is %d\n", quiet);
222 printf("verbose is %d\n", verbose);
223 printf("no-updates is %d\n", no_updates);
224 printf("ignore_errors is %d\n", ignore_errors);
225 printf("repository is %s\n", repository.c_str());
226 printf("savefile is %s\n", savefile.c_str());
227 printf("install_prefix is %s\n", install_prefix.c_str());
231 // Usually argv[command_index] will be a sub-command, unless
232 // --help or --version has been used.
234 // Always output the version number, irrespective of subsequent
235 // commands or any problems. This can be useful in batch jobs.
237 printf ("ecosconfig %s (%s %s)\n%s\n", TOOL_VERSION, __DATE__, __TIME__, TOOL_COPYRIGHT);
238 if (command_index == argc) {
242 // Cope with --help and any user errors. If --help is used then
243 // subsequent arguments should be ignored, as should any problems
244 // with the arguments. This allows the user to type a partial
245 // command, then switch to --help, and use shell history editing
246 // to complete/correct the command.
247 if (help || !args_ok || (command_index == argc)) {
249 return help ? EXIT_SUCCESS : EXIT_FAILURE;
252 // set the default save file
253 if (savefile.empty ()) { // if the save file was not specified on the command line
254 savefile = DEFAULT_SAVE_FILE; // use the default save file
257 // find the repository
258 if (repository.empty ()) { // if the repository was not specified on the command line
259 const char * env_var = getenv ("ECOS_REPOSITORY");
260 if (env_var) { // if the ECOS_REPOSITORY environment variable is defined
261 repository = env_var;
262 } else { // the ECOS_REPOSITORY environment variable is not defined
263 // assume that the tool is located in the root of the repository
265 char toolpath [_MAX_PATH + 1];
266 _fullpath (toolpath, argv [0], sizeof (toolpath)); // get the absolute path to the tool
268 // NOTE: portability problem. realpath() is not a POSIX function.
269 // Alternative code may be needed on some platforms.
270 char toolpath [MAXPATHLEN + 1];
271 realpath (argv [0], toolpath); // get the absolute path to the tool
273 repository = toolpath;
274 for (unsigned int n = repository.size () - 1; n > 0; n--) { // for each char starting at the tail
275 if (('\\' == repository [n]) || ('/' == repository [n])) { // if the char is a directory separator
276 repository.resize (n); // remove the filename from the filepath
283 repository = TRANSLATE_PATH(repository);
284 savefile = TRANSLATE_PATH(savefile);
285 install_prefix = TRANSLATE_PATH(install_prefix);
287 // Initialize the cdl_exec code (not quite sure why this needs a
288 // separate object rather than just a bunch of statics).
289 cdl_exec exec (trim_path (repository), savefile, trim_path (install_prefix), no_resolve);
290 cdl_exec::set_quiet_mode(quiet);
291 cdl_exec::set_verbose_mode(verbose);
292 cdl_exec::set_ignore_errors_mode(ignore_errors);
293 cdl_exec::set_no_updates_mode(no_updates);
294 if (enable_debug_set) {
295 cdl_exec::set_debug_level(debug_level);
298 // Now identify and process the sub-command.
299 const std::string command = argv [command_index];
303 if ("new" == command) {
304 // Usage: ecosconfig new <target> [template [version]]
305 if ((command_index == argc) || ((command_index + 3) <= argc)) {
308 // The default values for template and template_version
309 // are part of the cdl_exec class, so cdl_exec::cmd_new() has
310 // to be invoked with the right number of arguments.
311 if ((command_index + 1) == argc) {
312 status = exec.cmd_new(argv[command_index]);
313 } else if ((command_index + 2) == argc) {
314 status = exec.cmd_new(argv[command_index], argv[command_index + 1]);
316 status = exec.cmd_new(argv[command_index], argv[command_index + 1], argv[command_index + 2]);
319 } else if ("tree" == command) {
320 // Usage: ecosconfig tree
321 if (command_index == argc) {
322 status = exec.cmd_tree ();
326 } else if ("list" == command) {
327 // Usage: ecosconfig list
328 if (command_index == argc) {
329 status = exec.cmd_list ();
333 } else if ("check" == command) {
334 // Usage: ecosconfig check
335 if (command_index == argc) {
336 status = exec.cmd_check ();
340 } else if ("resolve" == command) {
341 // Usage: ecosconfig resolve
342 if (command_index == argc) {
343 status = exec.cmd_resolve ();
347 } else if ("add" == command) {
348 // Usage: ecosconfig add <package> [<package2> ...]
349 if (command_index < argc) {
350 std::vector<std::string> packages;
351 for (int n = command_index; n < argc; n++) {
352 packages.push_back (argv [n]);
354 status = exec.cmd_add (packages);
358 } else if ("remove" == command) {
359 // Usage: ecosconfig remove <package> [<package2> ...]
360 if (command_index < argc) {
361 std::vector<std::string> packages;
362 for (int n = command_index; n < argc; n++) {
363 packages.push_back (argv [n]);
365 status = exec.cmd_remove (packages);
369 } else if ("version" == command) {
370 // Usage: ecosconfig version <version> <package> [<package2> ...]
371 // Note that it is not possible to change several packages to different versions.
372 if (command_index + 1 < argc) {
373 std::vector<std::string> packages;
374 for (int n = command_index + 1; n < argc; n++) {
375 packages.push_back (argv [n]);
377 status = exec.cmd_version (argv [command_index], packages);
382 } else if ("target" == command) {
383 // Usage: ecosconfig target <target>
384 if (command_index + 1 == argc) {
385 status = exec.cmd_target (argv [command_index]);
390 } else if ("template" == command) {
391 // Usage: ecosconfig template <template> [<version>]
392 if (command_index + 1 == argc) {
393 status = exec.cmd_template (argv [command_index]);
394 } else if (command_index + 2 == argc) {
395 status = exec.cmd_template (argv [command_index], argv [command_index]);
400 } else if ("export" == command) {
401 // Usage: ecosconfige export <filename>
402 if (command_index + 1 == argc) {
403 std::string filename = std::string(argv[command_index]);
404 filename = TRANSLATE_PATH(filename);
405 status = exec.cmd_export(filename);
410 } else if ("import" == command) {
411 // Usage: ecosconfig import <filename>
412 if (command_index + 1 == argc) {
413 std::string filename = std::string(argv[command_index]);
414 filename = TRANSLATE_PATH(filename);
415 status = exec.cmd_import(filename);
424 return status ? EXIT_SUCCESS : EXIT_FAILURE;
427 // remove the trailing directory separator from a file path if present
428 std::string trim_path (const std::string input) {
429 std::string output = input;
430 if (! output.empty ()) {
431 const char last_char = output [output.size () - 1];
432 if (('\\' == last_char) || ('/' == last_char)) { // if the last char is a directory separator
433 output.resize (output.size () - 1); // remove the last char
439 // print a usage message
440 void usage_message () {
441 printf ("Usage: ecosconfig [ qualifier ... ] [ command ]\n");
442 printf (" commands are:\n");
443 printf (" list : list repository contents\n");
444 printf (" new TARGET [ TEMPLATE [ VERSION ] ] : create a configuration\n");
445 printf (" target TARGET : change the target hardware\n");
446 printf (" template TEMPLATE [ VERSION ] : change the template\n");
447 printf (" add PACKAGE [ PACKAGE ... ] : add package(s)\n");
448 printf (" remove PACKAGE [ PACKAGE ... ] : remove package(s)\n");
449 printf (" version VERSION PACKAGE [ PACKAGE ... ] : change version of package(s)\n");
450 printf (" export FILE : export minimal config info\n");
451 printf (" import FILE : import additional config info\n");
452 printf (" check : check the configuration\n");
453 printf (" resolve : resolve conflicts\n");
454 printf (" tree : create a build tree\n");
455 printf (" qualifiers are:\n");
456 printf (" --config=FILE : the configuration file\n");
457 printf (" --prefix=DIRECTORY : the install prefix\n");
458 printf (" --srcdir=DIRECTORY : the source repository\n");
459 printf (" --no-resolve : disable conflict resolution\n");
460 printf (" --version : show version and copyright\n");
461 printf (" -q, --quiet : reduce verbosity\n");
462 printf (" -v, --verbose : increase verbosity\n");
463 printf (" -i, --ignore-errors : ignore unresolved conflicts\n");
464 printf (" -n, --no-updates : read-only mode, do not modify the file system\n");
465 printf (" --enable-debug : enable debugging in this configuration\n");
466 printf (" --disable-debug : disable debugging in this configuration\n");
467 printf (" --help : display this message\n");