Example #1
0
Cmdline::Cmdline (int argc, char ** argv, Command * command)
: synopsis (command->getSynopsis ()), helpText (), invalidOpt (false),

  /*XXX: Step 2: initialise your option here.*/
  debug (), force (), load (), humanReadable (), help (), interactive (), minDepth (0), maxDepth (numeric_limits<int>::max ()),
  noNewline (), test (), recursive (), resolver (KDB_RESOLVER), strategy ("preserve"), verbose (), quiet (), version (), withoutElektra (),
  null (), first (true), second (true), third (true), withRecommends (false), all (), format (KDB_STORAGE), plugins ("sync"),
  globalPlugins ("spec"), pluginsConfig (""), color ("auto"), ns (""), editor (), bookmarks (), profile ("current"),

  executable (), commandName ()
{
	extern int optind;
	extern char * optarg;

	int opt;

	size_t optionPos;

	helpText += command->getShortHelpText ();
	helpText += "\n";
	helpText += command->getLongHelpText ();
	helpText += "\n";

	string allOptions = command->getShortOptions ();
	allOptions += "HVCp";

	// Make sure to use the unsorted allOptions for getopt to preserve argument chars : and ::
	std::set<string::value_type> unique_sorted_chars (allOptions.begin (), allOptions.end ());
	string acceptedOptions (unique_sorted_chars.begin (), unique_sorted_chars.end ());

	vector<option> long_options;
	/*XXX: Step 3: give it a long name.*/
	if (acceptedOptions.find ('a') != string::npos)
	{
		option o = { "all", no_argument, nullptr, 'a' };
		long_options.push_back (o);
		helpText += "-a --all                 Consider all of the keys.\n";
	}
	if (acceptedOptions.find ('d') != string::npos)
	{
		option o = { "debug", no_argument, nullptr, 'd' };
		long_options.push_back (o);
		helpText += "-d --debug               Give debug information or ask debug questions (in interactive mode).\n";
	}
	if (acceptedOptions.find ('f') != string::npos)
	{
		option o = { "force", no_argument, nullptr, 'f' };
		long_options.push_back (o);
		helpText += "-f --force               Force the action to be done.\n";
	}
	if (acceptedOptions.find ('l') != string::npos)
	{
		option o = { "load", no_argument, nullptr, 'f' };
		long_options.push_back (o);
		helpText += "-l --load                Load plugin even if system/elektra is available.\n";
	}
	if (acceptedOptions.find ('h') != string::npos)
	{
		option o = { "human-readable", no_argument, nullptr, 'h' };
		long_options.push_back (o);
		helpText += "-h --human-readable      Print numbers in an human readable way.\n";
	}
	if (acceptedOptions.find ('H') != string::npos)
	{
		option o = { "help", no_argument, nullptr, 'H' };
		long_options.push_back (o);
		helpText += "-H --help                Show the man page.\n";
	}
	if (acceptedOptions.find ('i') != string::npos)
	{
		option o = { "interactive", no_argument, nullptr, 'i' };
		long_options.push_back (o);
		helpText += "-i --interactive         Ask the user interactively.\n";
	}
	optionPos = acceptedOptions.find ('m');
	if (optionPos != string::npos)
	{
		acceptedOptions.insert (optionPos + 1, ":");
		option o = { "min-depth", required_argument, nullptr, 'm' };
		long_options.push_back (o);
		helpText += "-m --min-depth <min>     Specify the minimum depth (default 0).\n";
	}
	optionPos = acceptedOptions.find ('M');
	if (optionPos != string::npos)
	{
		acceptedOptions.insert (optionPos + 1, ":");
		option o = { "max-depth", required_argument, nullptr, 'M' };
		long_options.push_back (o);
		helpText += "-M --max-depth <max>     Specify the maximum depth (unlimited by default).\n";
	}
	if (acceptedOptions.find ('n') != string::npos)
	{
		option o = { "no-newline", no_argument, nullptr, 'n' };
		long_options.push_back (o);
		helpText += "-n --no-newline          Suppress the newline at the end of the output.\n";
	}
	if (acceptedOptions.find ('t') != string::npos)
	{
		option o = { "test", no_argument, nullptr, 't' };
		long_options.push_back (o);
		helpText += "-t --test                Test.\n";
	}
	if (acceptedOptions.find ('r') != string::npos)
	{
		option o = { "recursive", no_argument, nullptr, 'r' };
		long_options.push_back (o);
		helpText += "-r --recursive           Work in a recursive mode.\n";
	}
	optionPos = acceptedOptions.find ('R');
	if (optionPos != string::npos)
	{
		acceptedOptions.insert (optionPos + 1, ":");
		option o = { "resolver", required_argument, nullptr, 'R' };
		long_options.push_back (o);
		helpText += "-R --resolver <name>     Specify the resolver plugin to use.\n";
	}
	optionPos = acceptedOptions.find ('p');
	if (optionPos != string::npos)
	{
		acceptedOptions.insert (optionPos + 1, ":");
		option o = { "profile", required_argument, nullptr, 'p' };
		long_options.push_back (o);
		helpText += "-p --profile <name>      Use a different profile for kdb configuration.\n";
	}
	optionPos = acceptedOptions.find ('s');
	if (optionPos != string::npos)
	{
		acceptedOptions.insert (optionPos + 1, ":");
		option o = { "strategy", required_argument, nullptr, 's' };
		long_options.push_back (o);
		helpText += "-s --strategy <name>     Specify the strategy to resolve conflicts.\n";
	}
	if (acceptedOptions.find ('v') != string::npos)
	{
		option o = { "verbose", no_argument, nullptr, 'v' };
		long_options.push_back (o);
		helpText += "-v --verbose             Explain what is happening.\n";
	}
	if (acceptedOptions.find ('q') != string::npos)
	{
		option o = { "quiet", no_argument, nullptr, 'q' };
		long_options.push_back (o);
		helpText += "-q --quiet               Only print error messages.\n";
	}
	if (acceptedOptions.find ('V') != string::npos)
	{
		option o = { "version", no_argument, nullptr, 'V' };
		long_options.push_back (o);
		helpText += "-V --version             Print version info.\n";
	}
	if (acceptedOptions.find ('E') != string::npos)
	{
		option o = { "without-elektra", no_argument, nullptr, 'E' };
		long_options.push_back (o);
		helpText += "-E --without-elektra     Omit the `/elektra` directory.\n";
	}
	optionPos = acceptedOptions.find ('e');
	if (optionPos != string::npos)
	{
		acceptedOptions.insert (optionPos + 1, ":");
		option o = { "editor", required_argument, 0, 'e' };
		long_options.push_back (o);
		helpText += "-e --editor <editor>     Which external editor to use.\n";
	}
	if (acceptedOptions.find ('W') != string::npos)
	{
		option o = { "with-recommends", no_argument, nullptr, 'W' };
		long_options.push_back (o);
		helpText += "-W --with-recommends     Add recommended plugins.\n";
	}
	if (acceptedOptions.find ('0') != string::npos)
	{
		option o = { "null", no_argument, nullptr, '0' };
		long_options.push_back (o);
		helpText += "-0 --null                Use binary 0 termination.\n";
	}
	if (acceptedOptions.find ('1') != string::npos)
	{
		option o = { "first", no_argument, nullptr, '1' };
		long_options.push_back (o);
		helpText += "-1 --first               Suppress the first column.\n";
	}
	if (acceptedOptions.find ('2') != string::npos)
	{
		option o = { "second", no_argument, nullptr, '2' };
		long_options.push_back (o);
		helpText += "-2 --second              Suppress the second column.\n";
	}
	if (acceptedOptions.find ('3') != string::npos)
	{
		option o = { "third", no_argument, nullptr, '3' };
		long_options.push_back (o);
		helpText += "-3 --third               Suppress the third column.\n";
	}
	optionPos = acceptedOptions.find ('N');
	if (acceptedOptions.find ('N') != string::npos)
	{
		acceptedOptions.insert (optionPos + 1, ":");
		option o = { "namespace", required_argument, nullptr, 'N' };
		long_options.push_back (o);
		helpText += "-N --namespace <ns>      Specify the namespace to use for cascading keys.\n";
	}
	optionPos = acceptedOptions.find ('c');
	if (optionPos != string::npos)
	{
		acceptedOptions.insert (optionPos + 1, ":");
		option o = { "plugins-config", required_argument, nullptr, 'c' };
		long_options.push_back (o);
		helpText += "-c --plugins-config <c>  Add a plugin configuration.\n";
	}
	optionPos = acceptedOptions.find ('C');
	if (optionPos != string::npos)
	{
		acceptedOptions.insert (optionPos + 1, ":");
		option o = { "color", required_argument, nullptr, 'C' };
		long_options.push_back (o);
		helpText += "-C --color <when>       Print never/auto(default)/always colored output.\n";
	}

	int index = 0;
	option o = { nullptr, 0, nullptr, 0 };
	long_options.push_back (o);

	executable = argv[0];
	commandName = argv[1];

	opterr = 0;

	while ((opt = getopt_long (argc, argv, acceptedOptions.c_str (), &long_options[0], &index)) != EOF)
	{
		switch (opt)
		{
		case 'p':
			profile = optarg;
			break;
		default: // ignore everything else for now
			break;
		}
	}


	if (profile != "%")
	{
		try
		{
			using namespace kdb;
			/*XXX: Step 4: use default from KDB, if available.*/
			KDB kdb;
			KeySet conf;

			for (int i = 0; i <= 2; ++i)
			{
				std::string dirname;
				switch (i)
				{
				// prefer later dirnames (will override)
				case 0:
					dirname = "/sw/kdb/" + profile + "/";
					break; // legacy
				case 1:
					dirname = "/sw/elektra/kdb/#0/%/";
					break; // no profile
				case 2:
					dirname = "/sw/elektra/kdb/#0/" + profile + "/";
					break; // current profile
				}

				kdb.get (conf, dirname);

				Key k = conf.lookup (dirname + "resolver");
				if (k) resolver = k.get<string> ();

				k = conf.lookup (dirname + "format");
				if (k) format = k.get<string> ();

				k = conf.lookup (dirname + "plugins");
				if (k) plugins = k.get<string> ();

				k = conf.lookup (dirname + "plugins/global");
				if (k) globalPlugins = k.get<string> ();

				k = conf.lookup (dirname + "namespace");
				if (k) ns = k.get<string> ();

				k = conf.lookup (dirname + "verbose");
				if (k) verbose = k.get<bool> ();

				k = conf.lookup (dirname + "quiet");
				if (k) quiet = k.get<bool> ();

				k = conf.lookup (dirname + "editor");
				if (k) editor = k.get<string> ();

				k = conf.lookup (dirname + "recommends");
				if (k) withRecommends = k.get<bool> ();

				map nks = conf.get<map> (dirname + "bookmarks");
				bookmarks.insert (nks.begin (), nks.end ());

				k = conf.lookup (dirname + "color");
				if (k) color = k.get<std::string> ();
			}
		}
		catch (kdb::KDBException const & ce)
		{
			std::cerr << "Sorry, I could not fetch my own configuration:\n" << ce.what () << std::endl;
		}
	}

	// reinit
	index = 0;
	optind = 1;

	if (!dynamic_cast<ExternalCommand *> (command))
	{
		// do not print to stderr for external commands,
		// we do not know which options they have and
		// otherwise maybe wrong "invalid/unrecognized option"
		// are reported to stderr.
		opterr = 1;
	}

	while ((opt = getopt_long (argc, argv, acceptedOptions.c_str (), &long_options[0], &index)) != EOF)
	{
		switch (opt)
		{
		/*XXX: Step 5: and now process the option.*/
		case 'a':
			all = true;
			break;
		case 'C':
			color = optarg;
			if (color != "never" && color != "auto" && color != "always")
			{
				std::cerr << argv[0] << ": -C --color needs never, auto, or always as argument\n";
				invalidOpt = true;
			}
			break;
		case 'd':
			debug = true;
			break;
		case 'e':
			editor = optarg;
			break;
		case 'f':
			force = true;
			break;
		case 'h':
			humanReadable = true;
			break;
		case 'l':
			load = true;
			break;
		case 'H':
			help = true;
			break;
		case 'i':
			interactive = true;
			break;
		case 'm':
			try
			{
				minDepth = stoi (optarg);
			}
			catch (std::invalid_argument const & ia)
			{
				std::cerr << argv[0] << ": -m --min-depth needs a valid number as argument\n";
				invalidOpt = true;
			}
			break;
		case 'M':
			try
			{
				maxDepth = stoi (optarg);
			}
			catch (std::invalid_argument const & ia)
			{
				std::cerr << argv[0] << ": -M --max-depth needs a valid number as argument\n";
				invalidOpt = true;
			}

			if (maxDepth == -1)
			{
				maxDepth = numeric_limits<int>::max ();
			}
			break;
		case 'n':
			noNewline = true;
			break;
		case 't':
			test = true;
			break;
		case 'r':
			recursive = true;
			break;
		case 'p':
			break; // already handled above
		case 'R':
			resolver = optarg;
			break;
		case 's':
			strategy = optarg;
			break;
		case 'v':
			verbose = true;
			break;
		case 'q':
			quiet = true;
			break;
		case 'V':
			version = true;
			break;
		case 'E':
			withoutElektra = true;
			break;
		case 'W':
			withRecommends = true;
			break;
		case '0':
			null = true;
			break;
		case '1':
			first = false;
			break;
		case '2':
			second = false;
			break;
		case '3':
			third = false;
			break;
		case 'N':
			ns = optarg;
			break;
		case 'c':
			pluginsConfig = optarg;
			break;

		default:
			invalidOpt = true;
			break;
		}
	}

	if (quiet && verbose)
	{
		std::cout << "Both quiet and verbose is active: will suppress default messages, but print verbose messages" << std::endl;
	}

	if (ns.empty ())
	{
#ifndef _WIN32
		if (getuid () == 0 || geteuid () == 0)
		{
			ns = "system";
		}
		else
		{
			ns = "user";
		}
#else
		ns = "user";
#endif
	}

	optind++; // skip the command name
	while (optind < argc)
	{
		arguments.push_back (argv[optind++]);
	}

	// init colors
	hasStdColor (color);
	hasErrorColor (color);
}
Example #2
0
int MergeCommand::execute (Cmdline const & cl)
{

	if (cl.arguments.size () < 4)
	{
		throw invalid_argument ("wrong number of arguments, 4 needed");
	}

	Key oursRoot = cl.createKey (0);
	Key theirsRoot = cl.createKey (1);
	Key baseRoot = cl.createKey (2);
	Key resultRoot = cl.createKey (3);

	KeySet ours;
	KeySet theirs;
	KeySet base;

	{
		KDB lkdb;
		lkdb.get (ours, oursRoot);
		ours = ours.cut (oursRoot);
		ours.lookup (oursRoot, KDB_O_POP);
		if (cl.verbose) std::cout << "we got ours: " << oursRoot << " with keys " << ours << std::endl;
	}
	{
		KDB lkdb;
		lkdb.get (theirs, theirsRoot);
		theirs = theirs.cut (theirsRoot);
		ours.lookup (oursRoot, KDB_O_POP);
		if (cl.verbose) std::cout << "we got theirs: " << theirsRoot << " with keys " << theirs << std::endl;
	}
	{
		KDB lkdb;
		lkdb.get (base, baseRoot);
		base = base.cut (baseRoot);
		ours.lookup (oursRoot, KDB_O_POP);
		if (cl.verbose) std::cout << "we got base: " << baseRoot << " with keys " << base << std::endl;
	}

	KeySet resultKeys;
	kdb.get (resultKeys, resultRoot);

	KeySet discard = resultKeys.cut (resultRoot);
	if (discard.size () != 0)
	{
		if (cl.force)
		{
			if (cl.verbose)
			{
				std::cout << "will remove " << discard.size () << " keys, because -f was given" << std::endl;
			}
		}
		else
		{
			std::cerr << discard.size () << " keys exist in merge resultroot, will quit. Use -f to override the keys there."
				  << std::endl;
		}
	}

	MergeHelper helper;
	ThreeWayMerge merger;

	helper.configureMerger (cl, merger);

	MergeResult result = merger.mergeKeySet (
		MergeTask (BaseMergeKeys (base, baseRoot), OurMergeKeys (ours, oursRoot), TheirMergeKeys (theirs, theirsRoot), resultRoot));

	helper.reportResult (cl, result, cout, cerr);

	int ret = 0;
	if (!result.hasConflicts ())
	{
		resultKeys.append (result.getMergedKeys ());
		kdb.set (resultKeys, resultRoot);
	}
	else
	{
		ret = -1;
	}

	return ret;
}
Example #3
0
int EditorCommand::execute (Cmdline const & cl)
{
#ifdef _WIN32
	throw EditorNotAvailable ();
#endif

	int argc = cl.arguments.size ();
	if (argc < 1)
	{
		throw invalid_argument ("wrong number of arguments, 1 needed");
	}
	Key root = cl.createKey (0);

	KeySet ours;
	KDB kdb;
	kdb.get (ours, root);
	KeySet oursToEdit = ours.cut (root);
	KeySet original = oursToEdit.dup ();

	if (cl.strategy == "validate")
	{
		prependNamespace (oursToEdit, cl.ns);
		oursToEdit.cut (prependNamespace (root, cl.ns));
	}

	// export it to file
	string format = cl.format;
	if (argc > 1) format = cl.arguments[1];

	Modules modules;
	PluginPtr plugin = modules.load (format);

	tmpFile ();
	if (cl.verbose) std::cout << "filename set to " << filename << std::endl;
	Key errorKey (root);
	errorKey.setString (filename);

	if (plugin->set (oursToEdit, errorKey) == -1)
	{
		printWarnings (cerr, errorKey);
		printError (cerr, errorKey);
		return 11;
	}

	printWarnings (cerr, errorKey);


	// start editor
	if (cl.verbose) std::cout << "running editor with " << filename << std::endl;
	if (!cl.editor.empty ())
	{
		if (!runEditor (cl.editor, filename))
		{
			std::cerr << "Could not run editor " << cl.editor << std::endl;
			return 12;
		}
	}
	else
	{
		if (!runAllEditors (filename))
		{
			std::cerr << "Could not run any editor, please change /sw/elektra/kdb/#0/current/editor" << std::endl;
			return 12;
		}
	}

	// import from the file
	KeySet importedKeys;
	plugin->get (importedKeys, errorKey);
	importedKeys = importedKeys.cut (root);

	printWarnings (cerr, errorKey);
	printError (cerr, errorKey);

	if (cl.strategy == "validate")
	{
		applyMeta (importedKeys, original);
		kdb.set (importedKeys, root);
		printWarnings (cerr, root);
		return 0;
	}

	ThreeWayMerge merger;
	MergeHelper helper;

	helper.configureMerger (cl, merger);
	MergeResult result = merger.mergeKeySet (
		MergeTask (BaseMergeKeys (oursToEdit, root), OurMergeKeys (oursToEdit, root), TheirMergeKeys (importedKeys, root), root));

	helper.reportResult (cl, result, cout, cerr);

	int ret = 13;
	if (!result.hasConflicts ())
	{
		if (cl.verbose)
		{
			cout << "The merged keyset with strategy " << cl.strategy << " is:" << endl;
			cout << result.getMergedKeys ();
		}

		KeySet resultKeys = result.getMergedKeys ();
		if (cl.verbose) std::cout << "about to write result keys " << resultKeys << std::endl;
		ours.append (resultKeys);
		try
		{
			kdb.set (ours, root);
			if (cl.verbose) std::cout << "successful, cleaning up " << filename << std::endl;
			unlink (filename.c_str ());
			ret = 0;
		}
		catch (KDBException const & e)
		{
			std::cout << "Import of configuration failed with the error:\n";
			std::cout << e.what ();
			std::cout << "\n\n";
			std::cout << "Your changes are not lost." << std::endl;
			std::cout << "Please fix, import and remove \"" << filename << '"' << std::endl;
			ret = 14;
		}
	}
	else
	{
		std::cout << "Import not successful, please import and remove \"" << filename << '"' << std::endl;
	}

	return ret;
}