/** * When the framework is not found, display detailed error message * about available frameworks and installation of new framework. */ void fx_resolver_t::display_missing_framework_error( const pal::string_t& fx_name, const pal::string_t& fx_version, const pal::string_t& fx_dir, const pal::string_t& dotnet_root) { std::vector<framework_info> framework_infos; pal::string_t fx_ver_dirs; if (fx_dir.length()) { fx_ver_dirs = fx_dir; framework_info::get_all_framework_infos(get_directory(fx_dir), fx_name, &framework_infos); } else { fx_ver_dirs = dotnet_root; } framework_info::get_all_framework_infos(dotnet_root, fx_name, &framework_infos); // Display the error message about missing FX. if (fx_version.length()) { trace::error(_X("The specified framework '%s', version '%s' was not found."), fx_name.c_str(), fx_version.c_str()); } else { trace::error(_X("The specified framework '%s' was not found."), fx_name.c_str()); } if (framework_infos.size()) { trace::error(_X(" - The following frameworks were found:")); for (const framework_info& info : framework_infos) { trace::error(_X(" %s at [%s]"), info.version.as_str().c_str(), info.path.c_str()); } } else { trace::error(_X(" - No frameworks were found.")); } trace::error(_X("")); trace::error(_X("You can resolve the problem by installing the specified framework and/or SDK.")); trace::error(_X("")); trace::error(_X("The .NET Core frameworks can be found at:")); trace::error(_X(" - %s"), DOTNET_CORE_DOWNLOAD_URL); }
bool LongFile::IsPathNotFullyQualified(const pal::string_t& path) { if (path.length() < 2) { return true; // It isn't fixed, it must be relative. There is no way to specify a fixed path with one character (or less). } if (IsDirectorySeparator(path[0])) { return !IsDirectorySeparator(path[1]); // There is no valid way to specify a relative path with two initial slashes } return !((path.length() >= 3) //The only way to specify a fixed path that doesn't begin with two slashes is the drive, colon, slash format- "i.e. C:\" && (path[1] == VolumeSeparatorChar) && IsDirectorySeparator(path[2])); }
void get_tpafile_path(const pal::string_t& app_base, const pal::string_t& app_name, pal::string_t& tpapath) { tpapath.reserve(app_base.length() + app_name.length() + 5); tpapath.append(app_base); tpapath.push_back(DIR_SEPARATOR); // Remove the extension from the app_name auto ext_location = app_name.find_last_of('.'); if (ext_location != std::string::npos) { tpapath.append(app_name.substr(0, ext_location)); } else { tpapath.append(app_name); } tpapath.append(_X(".deps")); }
/** * Given path to app binary, say app.dll or app.exe, retrieve the app.deps.json. */ pal::string_t get_deps_from_app_binary(const pal::string_t& app_base, const pal::string_t& app) { pal::string_t deps_file; auto app_name = get_filename(app); deps_file.reserve(app_base.length() + 1 + app_name.length() + 5); deps_file.append(app_base); if (!app_base.empty() && app_base.back() != DIR_SEPARATOR) { deps_file.push_back(DIR_SEPARATOR); } deps_file.append(app_name, 0, app_name.find_last_of(_X("."))); deps_file.append(_X(".deps.json")); return deps_file; }
bool read_field(pal::string_t line, int& offset, pal::string_t& value_recv) { // The first character should be a '"' if (line[offset] != '"') { trace::error(_X("error reading TPA file")); return false; } offset++; // Set up destination buffer (it can't be bigger than the original line) pal::char_t buf[PATH_MAX]; auto buf_offset = 0; // Iterate through characters in the string for (; offset < line.length(); offset++) { // Is this a '\'? if (line[offset] == '\\') { // Skip this character and read the next character into the buffer offset++; buf[buf_offset] = line[offset]; } // Is this a '"'? else if (line[offset] == '\"') { // Done! Advance to the pointer after the input offset++; break; } else { // Take the character buf[buf_offset] = line[offset]; } buf_offset++; } buf[buf_offset] = '\0'; value_recv.assign(buf); // Consume the ',' if we have one if (line[offset] == ',') { offset++; } return true; }
// For some distros, we don't want to use the full version from VERSION_ID. One example is // Red Hat Enterprise Linux, which includes a minor version in their VERSION_ID but minor // versions are backwards compatable. // // In this case, we'll normalized RIDs like 'rhel.7.2' and 'rhel.7.3' to a generic // 'rhel.7'. This brings RHEL in line with other distros like CentOS or Debian which // don't put minor version numbers in their VERSION_ID fields because all minor versions // are backwards compatible. static pal::string_t normalize_linux_rid(pal::string_t rid) { pal::string_t rhelPrefix(_X("rhel.")); if (rid.compare(0, rhelPrefix.length(), rhelPrefix) == 0) { size_t minorVersionSeparatorIndex = rid.find(_X("."), rhelPrefix.length()); if (minorVersionSeparatorIndex != std::string::npos) { rid.erase(minorVersionSeparatorIndex, rid.length() - minorVersionSeparatorIndex); } } return rid; }
bool deps_entry_t::to_path(const pal::string_t& base, bool look_in_base, pal::string_t* str) const { pal::string_t& candidate = *str; candidate.clear(); // Base directory must be present to obtain full path if (base.empty()) { return false; } // Entry relative path contains '/' separator, sanitize it to use // platform separator. Perf: avoid extra copy if it matters. pal::string_t pal_relative_path = relative_path; if (_X('/') != DIR_SEPARATOR) { replace_char(&pal_relative_path, _X('/'), DIR_SEPARATOR); } // Reserve space for the path below candidate.reserve(base.length() + pal_relative_path.length() + 3); candidate.assign(base); pal::string_t sub_path = look_in_base ? get_filename(pal_relative_path) : pal_relative_path; append_path(&candidate, sub_path.c_str()); bool exists = pal::file_exists(candidate); const pal::char_t* query_type = look_in_base ? _X("Local") : _X("Relative"); if (!exists) { trace::verbose(_X(" %s path query did not exist %s"), query_type, candidate.c_str()); candidate.clear(); } else { trace::verbose(_X(" %s path query exists %s"), query_type, candidate.c_str()); } return exists; }
// ----------------------------------------------------------------------------- // Given a "base" directory, yield the relative path of this file in the package // layout if the entry hash matches the hash file in the "base" directory // // Parameters: // base - The base directory to look for the relative path of this entry and // the hash file. // str - If the method returns true, contains the file path for this deps // entry relative to the "base" directory // // Description: // Looks for a file named "{PackageName}.{PackageVersion}.nupkg.{HashAlgorithm}" // If the deps entry's {HashAlgorithm}-{HashValue} matches the contents then // yields the relative path of this entry in the "base" dir. // // Returns: // If the file exists in the path relative to the "base" directory and there // was hash file match with this deps entry. // // See: to_full_path(base, str) // bool deps_entry_t::to_hash_matched_path(const pal::string_t& base, pal::string_t* str) const { pal::string_t& candidate = *str; candidate.clear(); // Base directory must be present to perform hash lookup. if (base.empty()) { return false; } // First detect position of hyphen in [Algorithm]-[Hash] in the string. size_t pos = library_hash.find(_X("-")); if (pos == 0 || pos == pal::string_t::npos) { trace::verbose(_X("Invalid hash %s value for deps file entry: %s"), library_hash.c_str(), library_name.c_str()); return false; } // Build the relative hash path (what is added to the package directory path). pal::string_t relative_hash_path; if (library_hash_path.empty()) { // Reserve approx 8 char_t's for the algorithm name. relative_hash_path.reserve(library_name.length() + 1 + library_version.length() + 16); relative_hash_path.append(library_name); relative_hash_path.append(_X(".")); relative_hash_path.append(library_version); relative_hash_path.append(_X(".nupkg.")); relative_hash_path.append(library_hash.substr(0, pos)); } else { relative_hash_path.assign(library_hash_path); } // Build the directory that contains the hash file. pal::string_t hash_file; if (library_path.empty()) { hash_file.reserve(base.length() + 1 + library_name.length() + 1 + library_version.length() + 1 + relative_hash_path.length()); hash_file.assign(base); append_path(&hash_file, library_name.c_str()); append_path(&hash_file, library_version.c_str()); } else { hash_file.reserve(base.length() + 1 + library_path.length() + 1 + relative_hash_path.length()); hash_file.assign(base); append_path(&hash_file, library_path.c_str()); } // Append the relative path to the hash file. append_path(&hash_file, relative_hash_path.c_str()); // Read the contents of the hash file. pal::ifstream_t fstream(hash_file); if (!fstream.good()) { trace::verbose(_X("The hash file is invalid [%s]"), hash_file.c_str()); return false; } // Obtain the hash from the file. std::string hash; hash.assign(pal::istreambuf_iterator_t(fstream), pal::istreambuf_iterator_t()); pal::string_t pal_hash; if (!pal::utf8_palstring(hash.c_str(), &pal_hash)) { return false; } // Check if contents match deps entry. pal::string_t entry_hash = library_hash.substr(pos + 1); if (entry_hash != pal_hash) { trace::verbose(_X("The file hash [%s][%d] did not match entry hash [%s][%d]"), pal_hash.c_str(), pal_hash.length(), entry_hash.c_str(), entry_hash.length()); return false; } // All good, just append the relative dir to base. return to_full_path(base, &candidate); }
bool ends_with(const pal::string_t& value, const pal::string_t& suffix) { return suffix.length() <= value.length() && (0 == value.compare(value.length() - suffix.length(), suffix.length(), suffix)); }
/*static*/ void framework_info::get_all_framework_infos( const pal::string_t& own_dir, const pal::string_t& fx_name, std::vector<framework_info>* framework_infos) { std::vector<pal::string_t> global_dirs; bool multilevel_lookup = multilevel_lookup_enabled(); // own_dir contains DIR_SEPARATOR appended that we need to remove. pal::string_t own_dir_temp = own_dir; remove_trailing_dir_seperator(&own_dir_temp); std::vector<pal::string_t> hive_dir; hive_dir.push_back(own_dir_temp); if (multilevel_lookup && pal::get_global_dotnet_dirs(&global_dirs)) { for (pal::string_t dir : global_dirs) { if (!pal::are_paths_equal_with_normalized_casing(dir, own_dir_temp)) { hive_dir.push_back(dir); } } } for (pal::string_t dir : hive_dir) { auto fx_shared_dir = dir; append_path(&fx_shared_dir, _X("shared")); if (pal::directory_exists(fx_shared_dir)) { std::vector<pal::string_t> fx_names; if (fx_name.length()) { // Use the provided framework name fx_names.push_back(fx_name); } else { // Read all frameworks, including "Microsoft.NETCore.App" pal::readdir_onlydirectories(fx_shared_dir, &fx_names); } for (pal::string_t fx_name : fx_names) { auto fx_dir = fx_shared_dir; append_path(&fx_dir, fx_name.c_str()); if (pal::directory_exists(fx_dir)) { trace::verbose(_X("Gathering FX locations in [%s]"), fx_dir.c_str()); std::vector<pal::string_t> versions; pal::readdir_onlydirectories(fx_dir, &versions); for (const auto& ver : versions) { // Make sure we filter out any non-version folders. fx_ver_t parsed; if (fx_ver_t::parse(ver, &parsed, false)) { trace::verbose(_X("Found FX version [%s]"), ver.c_str()); framework_info info(fx_name, fx_dir, parsed); framework_infos->push_back(info); } } } } } } std::sort(framework_infos->begin(), framework_infos->end(), compare_by_name_and_version); }