bool w_cmd_realpath_root(json_ref& args, char** errmsg) { const char *path; if (json_array_size(args) < 2) { ignore_result(asprintf(errmsg, "wrong number of arguments")); return false; } path = json_string_value(json_array_get(args, 1)); if (!path) { ignore_result(asprintf(errmsg, "second argument must be a string")); return false; } try { auto resolved = realPath(path); args.array()[1] = w_string_to_json(resolved); return true; } catch (const std::exception &exc) { watchman::log(watchman::DBG, "w_cmd_realpath_root: path ", path, " does not resolve: ", exc.what(), "\n"); // We don't treat this as an error; the caller will subsequently // fail and perform their usual error handling return true; } }
// Given a target of the form "absolute_path/filename", return // realpath(absolute_path) + filename, where realpath(absolute_path) resolves // all the symlinks in absolute_path. static w_string get_normalized_target(const w_string& target) { int err; w_assert( w_string_path_is_absolute(target), "get_normalized_target: path %s is not absolute\n", target.c_str()); auto dir_name = target.dirName(); auto dir_name_real = realPath(dir_name.c_str()); err = errno; if (dir_name_real) { auto file_name = target.baseName(); return w_string::pathCat({dir_name_real, file_name}); } errno = err; return nullptr; }
// For watch-project, take a root path string and resolve the // containing project directory, then update the args to reflect // that path. // relpath will hold the path to the project dir, relative to the // watched dir. If it is NULL it means that the project dir is // equivalent to the watched dir. static w_string resolve_projpath(const json_ref& args, char** errmsg, w_string& relpath) { const char* path; bool enforcing; if (json_array_size(args) < 2) { ignore_result(asprintf(errmsg, "wrong number of arguments")); return nullptr; } path = json_string_value(json_array_get(args, 1)); if (!path) { ignore_result(asprintf(errmsg, "second argument must be a string")); return nullptr; } auto resolved = realPath(path); auto root_files = cfg_compute_root_files(&enforcing); if (!root_files) { ignore_result(asprintf(errmsg, "resolve_projpath: error computing root_files configuration value, " "consult your log file at %s for more details", log_name)); return nullptr; } // See if we're requesting something in a pre-existing watch w_string_piece prefix; w_string_piece relpiece; if (findEnclosingRoot(resolved, prefix, relpiece)) { relpath = relpiece.asWString(); resolved = prefix.asWString(); json_array_set_new(args, 1, w_string_to_json(resolved)); return resolved; } auto resolvedpiece = resolved.piece(); if (find_project_root(root_files, resolvedpiece, relpiece)) { relpath = relpiece.asWString(); resolved = resolvedpiece.asWString(); json_array_set_new(args, 1, w_string_to_json(resolved)); return resolved; } if (!enforcing) { // We'll use the path they originally requested return resolved; } // Convert root files to comma delimited string for error message auto root_files_list = cfg_pretty_print_root_files(root_files); ignore_result(asprintf( errmsg, "resolve_projpath: None of the files listed in global config " "root_files are present in path `%s` or any of its " "parent directories. root_files is defined by the " "`%s` config file and includes %s. " "One or more of these files must be present in order to allow " "a watch. Try pulling and checking out a newer version of the project?", path, cfg_get_global_config_file_path().c_str(), root_files_list.c_str())); return nullptr; }