Beispiel #1
0
void deps_resolver_t::resolve_tpa_list(
        const pal::string_t& clr_dir,
        pal::string_t* output)
{
    const std::vector<deps_entry_t> empty(0);

    // Obtain the local assemblies in the app dir.
    get_dir_assemblies(m_app_dir, _X("local"), &m_local_assemblies);
    if (m_portable)
    {
        // For portable also obtain FX dir assemblies.
        get_dir_assemblies(m_fx_dir, _X("fx"), &m_fx_assemblies);
    }

    std::unordered_set<pal::string_t> items;

    auto process_entry = [&](const pal::string_t& deps_dir, deps_json_t* deps, const dir_assemblies_t& dir_assemblies, const deps_entry_t& entry)
    {
        if (items.count(entry.asset_name))
        {
            return;
        }

        pal::string_t candidate;

        trace::info(_X("Processing TPA for deps entry [%s, %s, %s]"), entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str());

        // Try to probe from the shared locations.
        if (probe_entry_in_configs(entry, &candidate))
        {
            add_tpa_asset(entry.asset_name, candidate, &items, output);
        }
        // The rid asset should be picked up from app relative subpath.
        else if (entry.is_rid_specific && entry.to_rel_path(deps_dir, &candidate))
        {
            add_tpa_asset(entry.asset_name, candidate, &items, output);
        }
        // The rid-less asset should be picked up from the app base.
        else if (dir_assemblies.count(entry.asset_name))
        {
            add_tpa_asset(entry.asset_name, dir_assemblies.find(entry.asset_name)->second, &items, output);
        }
        else
        {
            // FIXME: Consider this error as a fail fast?
            trace::verbose(_X("Error: Could not resolve path to assembly: [%s, %s, %s]"), entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str());
        }
    };
    
    const auto& deps_entries = m_deps->get_entries(deps_entry_t::asset_types::runtime);
    std::for_each(deps_entries.begin(), deps_entries.end(), [&](const deps_entry_t& entry) {
        process_entry(m_app_dir, m_deps.get(), m_local_assemblies, entry);
    });

    // Finally, if the deps file wasn't present or has missing entries, then
    // add the app local assemblies to the TPA.
    for (const auto& kv : m_local_assemblies)
    {
        add_tpa_asset(kv.first, kv.second, &items, output);
    }

    const auto& fx_entries = m_portable ? m_fx_deps->get_entries(deps_entry_t::asset_types::runtime) : empty;
    std::for_each(fx_entries.begin(), fx_entries.end(), [&](const deps_entry_t& entry) {
        process_entry(m_fx_dir, m_fx_deps.get(), m_fx_assemblies, entry);
    });

    for (const auto& kv : m_fx_assemblies)
    {
        add_tpa_asset(kv.first, kv.second, &items, output);
    }
}
Beispiel #2
0
/**
 *  Resovle the TPA assembly locations
 */
bool deps_resolver_t::resolve_tpa_list(
        pal::string_t* output,
        std::unordered_set<pal::string_t>* breadcrumb)
{
    const std::vector<deps_entry_t> empty(0);
    std::unordered_set<pal::string_t> items;

    auto process_entry = [&](const pal::string_t& deps_dir, deps_json_t* deps, const deps_entry_t& entry) -> bool
    {
        if (entry.is_serviceable)
        {
            breadcrumb->insert(entry.library_name + _X(",") + entry.library_version);
            breadcrumb->insert(entry.library_name);
        }
        if (items.count(entry.asset_name))
        {
            return true;
        }
        // Ignore placeholders
        if (ends_with(entry.relative_path, _X("/_._"), false))
        {
            return true;
        }

        pal::string_t candidate;

        trace::info(_X("Processing TPA for deps entry [%s, %s, %s]"), entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str());

        if (probe_deps_entry(entry, deps_dir, &candidate))
        {
            add_tpa_asset(entry.asset_name, candidate, &items, output);
            return true;
        }
        else
        {
            trace::error(_X("Error: assembly specified in the dependencies manifest was not found -- package: '%s', version: '%s', path: '%s'"), 
                entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str());
            return false;
        }
    };

    // First add managed assembly to the TPA.
    // TODO: Remove: the deps should contain the managed DLL.
    // Workaround for: csc.deps.json doesn't have the csc.dll
    pal::string_t managed_app_asset = get_filename_without_ext(m_managed_app);
    add_tpa_asset(managed_app_asset, m_managed_app, &items, output);

    const auto& deps_entries = m_deps->get_entries(deps_entry_t::asset_types::runtime);
    for (const auto& entry : deps_entries)
    {
        if (!process_entry(m_app_dir, m_deps.get(), entry))
        {
            return false;
        }
    }

    // Finally, if the deps file wasn't present or has missing entries, then
    // add the app local assemblies to the TPA.
    if (!m_deps->exists())
    {
        dir_assemblies_t local_assemblies;

        // Obtain the local assemblies in the app dir.
        get_dir_assemblies(m_app_dir, _X("local"), &local_assemblies);
        for (const auto& kv : local_assemblies)
        {
            add_tpa_asset(kv.first, kv.second, &items, output);
        }
    }

    // Probe FX deps entries after app assemblies are added.
    const auto& fx_entries = m_portable ? m_fx_deps->get_entries(deps_entry_t::asset_types::runtime) : empty;
    for (const auto& entry : fx_entries)
    {
        if (!process_entry(m_fx_dir, m_fx_deps.get(), entry))
        {
            return false;
        }
    }

    return true;
}
Beispiel #3
0
/**
 *  Resolve the TPA assembly locations
 */
bool deps_resolver_t::resolve_tpa_list(
        pal::string_t* output,
        std::unordered_set<pal::string_t>* breadcrumb,
        bool ignore_missing_assemblies)
{
    const std::vector<deps_entry_t> empty(0);
    name_to_resolved_asset_map_t items;

    auto process_entry = [&](const pal::string_t& deps_dir, const deps_entry_t& entry, int fx_level) -> bool
    {
        if (breadcrumb != nullptr && entry.is_serviceable)
        {
            breadcrumb->insert(entry.library_name + _X(",") + entry.library_version);
            breadcrumb->insert(entry.library_name);
        }

        // Ignore placeholders
        if (ends_with(entry.asset.relative_path, _X("/_._"), false))
        {
            return true;
        }

        trace::info(_X("Processing TPA for deps entry [%s, %s, %s]"), entry.library_name.c_str(), entry.library_version.c_str(), entry.asset.relative_path.c_str());

        pal::string_t resolved_path;

        name_to_resolved_asset_map_t::iterator existing = items.find(entry.asset.name);
        if (existing == items.end())
        {
            if (probe_deps_entry(entry, deps_dir, fx_level, &resolved_path))
            {
                deps_resolved_asset_t resolved_asset(entry.asset, resolved_path);
                add_tpa_asset(resolved_asset, &items);
                return true;
            }

            return report_missing_assembly_in_manifest(entry, ignore_missing_assemblies);
        }
        else
        {
            // Verify the extension is the same as the previous verified entry
            if (get_deps_filename(entry.asset.relative_path) != get_filename(existing->second.resolved_path))
            {
                trace::error(
                    DuplicateAssemblyWithDifferentExtensionMessage.c_str(),
                    entry.deps_file.c_str(),
                    entry.library_name.c_str(),
                    entry.library_version.c_str(),
                    entry.asset.relative_path.c_str(),
                    existing->second.resolved_path.c_str());

                return false;
            }

            deps_resolved_asset_t* existing_entry = &existing->second;

            // If deps entry is same or newer than existing, then see if it should be replaced
            if (entry.asset.assembly_version > existing_entry->asset.assembly_version ||
                (entry.asset.assembly_version == existing_entry->asset.assembly_version && entry.asset.file_version >= existing_entry->asset.file_version))
            {
                if (probe_deps_entry(entry, deps_dir, fx_level, &resolved_path))
                {
                    // If the path is the same, then no need to replace
                    if (resolved_path != existing_entry->resolved_path)
                    {
                        trace::verbose(_X("Replacing deps entry [%s, AssemblyVersion:%s, FileVersion:%s] with [%s, AssemblyVersion:%s, FileVersion:%s]"),
                            existing_entry->resolved_path.c_str(), existing_entry->asset.assembly_version.as_str().c_str(), existing_entry->asset.file_version.as_str().c_str(),
                            resolved_path.c_str(), entry.asset.assembly_version.as_str().c_str(), entry.asset.file_version.as_str().c_str());

                        existing_entry = nullptr;
                        items.erase(existing);

                        deps_asset_t asset(entry.asset.name, entry.asset.relative_path, entry.asset.assembly_version, entry.asset.file_version);
                        deps_resolved_asset_t resolved_asset(asset, resolved_path);
                        add_tpa_asset(resolved_asset, &items);
                    }
                }
                else if (fx_level != 0)
                {
                    // The framework is missing a newer package, so this is an error.
                    // For compat, it is not an error for the app; this can occur for the main application assembly when using --depsfile
                    // and the app assembly does not exist with the deps file.
                    return report_missing_assembly_in_manifest(entry);
                }
            }

            return true;
        }
    };

    // We do not support self-contained in a libhost scenario since in the self-contained scenario,
    // we cannot determine what assemblies are framework assemblies, and what assemblies are app-local assemblies.
    if (m_host_mode != host_mode_t::libhost)
    {
        // First add managed assembly to the TPA.
        // TODO: Remove: the deps should contain the managed DLL.
        // Workaround for: csc.deps.json doesn't have the csc.dll
        deps_asset_t asset(get_filename_without_ext(m_managed_app), get_filename(m_managed_app), version_t(), version_t());
        deps_resolved_asset_t resolved_asset(asset, m_managed_app);
        add_tpa_asset(resolved_asset, &items);

        // Add the app's entries
        const auto& deps_entries = get_deps().get_entries(deps_entry_t::asset_types::runtime);
        for (const auto& entry : deps_entries)
        {
            if (!process_entry(m_app_dir, entry, 0))
            {
                return false;
            }
        }

        // If the deps file wasn't present or has missing entries, then
        // add the app local assemblies to the TPA. This is only valid
        // in non-libhost scenarios (e.g. comhost).
        if (!get_deps().exists())
        {
            // Obtain the local assemblies in the app dir.
            get_dir_assemblies(m_app_dir, _X("local"), &items);
        }
    }

    // There should be no additional deps files in a libhost scenario.
    // See comments during additional deps.json resolution.
    assert(m_additional_deps.empty() || m_host_mode != host_mode_t::libhost);

    // If additional deps files were specified that need to be treated as part of the
    // application, then add them to the mix as well.
    for (const auto& additional_deps : m_additional_deps)
    {
        auto additional_deps_entries = additional_deps->get_entries(deps_entry_t::asset_types::runtime);
        for (auto entry : additional_deps_entries)
        {
            if (!process_entry(m_app_dir, entry, 0))
            {
                return false;
            }
        }
    }

    // Probe FX deps entries after app assemblies are added.
    for (int i = 1; i < m_fx_definitions.size(); ++i)
    {
        const auto& deps_entries = m_is_framework_dependent ? m_fx_definitions[i]->get_deps().get_entries(deps_entry_t::asset_types::runtime) : empty;
        for (const auto& entry : deps_entries)
        {
            if (!process_entry(m_fx_definitions[i]->get_dir(), entry, i))
            {
                return false;
            }
        }
    }

    // Convert the paths into a string and return it 
    for (const auto& item : items)
    {
        // Workaround for CoreFX not being able to resolve sym links.
        pal::string_t real_asset_path = item.second.resolved_path;
        pal::realpath(&real_asset_path);
        output->append(real_asset_path);
        output->push_back(PATH_SEPARATOR);
    }

    return true;
}