You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Conception/drake-master/multibody/parsing/package_map.h

228 lines
9.7 KiB

#pragma once
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "drake/common/drake_copyable.h"
#include "drake/common/fmt_ostream.h"
#include "drake/common/name_value.h"
namespace drake {
namespace multibody {
/** Maps ROS package names to their full path on the local file system. It is
used by the SDF and URDF parsers when parsing files that reference ROS packages
for resources like mesh files. This class can also download remote packages from
the internet on an as-needed basis via AddRemote(). */
class PackageMap final {
public:
/** A constructor that initializes a default map containing only the top-level
`drake` manifest. See PackageMap::MakeEmpty() to create an empty map. */
PackageMap();
/** @name Implements CopyConstructible, CopyAssignable, MoveConstructible,
MoveAssignable */
//@{
PackageMap(const PackageMap&);
PackageMap& operator=(const PackageMap&);
PackageMap(PackageMap&&);
PackageMap& operator=(PackageMap&&);
//@}
~PackageMap();
/** A factory method that initializes an empty map. */
static class PackageMap MakeEmpty();
/** @name Functions for looking up packages in the map */
///@{
/** Returns the number of entries in this PackageMap. */
int size() const;
/** Returns the package names in this PackageMap. The order of package names
returned is unspecified. */
std::vector<std::string> GetPackageNames() const;
/** Returns true if and only if this PackageMap contains `package_name`. */
bool Contains(const std::string& package_name) const;
/** Obtains the path associated with package `package_name`. Aborts if no
package named `package_name` exists in this PackageMap.
@param[out] deprecated_message When passed as nullptr (its default value),
then in case the `package_name` is deprecated a deprecation message will be
logged. When passed as non-nullptr the deprecation message will be output into
this argument and will not be logged; if the `package_name` is not deprecated,
the message will be set to nullopt. */
const std::string& GetPath(
const std::string& package_name,
std::optional<std::string>* deprecated_message = nullptr) const;
///@}
/** @name Functions for adding packages to the map */
///@{
/** Adds package `package_name` and its path, `package_path`. Throws if
`package_name` is already present in this PackageMap with a different path, or
if `package_path` does not exist. */
void Add(const std::string& package_name, const std::string& package_path);
/** Adds all packages from `other_map` into `this`. Throws if `other` contains
a package with the same `package_name` as one already in this map but with
incompatible details (e.g., a different local path). */
void AddMap(const PackageMap& other_map);
/** Adds an entry into this PackageMap for the given `package.xml` filename.
Throws if `filename` does not exist or its embedded name already exists in
this map. */
void AddPackageXml(const std::string& filename);
/** Parameters used for AddRemote(). */
struct RemoteParams {
template <typename Archive>
void Serialize(Archive* a) {
a->Visit(DRAKE_NVP(urls));
a->Visit(DRAKE_NVP(sha256));
a->Visit(DRAKE_NVP(archive_type));
a->Visit(DRAKE_NVP(strip_prefix));
}
/** Returns the JSON serialization of these params. */
std::string ToJson() const;
/** Equality operator. */
friend bool operator==(const RemoteParams&, const RemoteParams&);
/** The list of remote URLs for this resource. The urls are used in the
other they appear here, so preferred mirror(s) should come first. Valid
methods are "http://" or "https://" or "file://". */
std::vector<std::string> urls;
/** The cryptographic checksum of the file to be downloaded, as a
64-character hexadecimal string. */
std::string sha256;
/** (Optional) The archive type of the downloaded file. Valid options are
"zip", "tar", "gztar", "bztar", or "xztar". By default, the archive type is
determined from the file extension of the URL; in case the URL has no
filename extension, you should explicitly specify one here. */
std::optional<std::string> archive_type;
/** (Optional) A directory prefix to remove from the extracted files. In
many cases, an archive will prefix all filenames with something like
"package-v1.2.3/" so that it extracts into a convenient directory. This
option will discard that common prefix when extracting the archive for the
PackageMap. It is an error if the archive does not contain any diectory with
this prefix, but if there are files outside of this directory they will be
silently discarded. */
std::optional<std::string> strip_prefix;
};
/** Adds an entry into this PackageMap for the given `package_name`, which
will be downloaded from the internet (with local caching). The data will not
be downloaded until necessary, i.e., when GetPath() is first called for the
`package_name`. Throws if the `package_name` or `params` are invalid.
Downloading requires a valid `/usr/bin/python3` interpreter, which will be
invoked as a subprocess.
See \ref allow_network "DRAKE_ALLOW_NETWORK" for an environment variable
option to disable network fetching. %AddRemote may still be used even with
network fetching disabled -- in that case, the urls must contain a "file://"
URL or the download cache must already contain a previously-downloaded copy
of the package (with the same sha256 checksum). */
void AddRemote(std::string package_name, RemoteParams params);
/** Crawls down the directory tree starting at `path` searching for
directories containing the file `package.xml`. For each of these directories,
this method adds a new entry into this PackageMap where the key is the package
name as specified within `package.xml` and the directory's path is the value.
If a package already known by the PackageMap is found again with a conflicting
path, a warning is logged and the original path is kept. If the path does not
exist or is unreadable, a warning is logged. */
void PopulateFromFolder(const std::string& path);
/** Obtains one or more paths from environment variable
`environment_variable`. Crawls downward through the directory tree(s) starting
from the path(s) searching for `package.xml` files. For each of these files,
this method adds a new entry into this PackageMap where the key is the package
name as specified within `package.xml` and the value is the path to the
`package.xml` file. Multiple paths can be specified by separating them using
the ':' symbol. For example, the environment variable can contain [path
1]:[path 2]:[path 3] to search three different paths.
If a package already known by the PackageMap is found again with a conflicting
path, a warning is logged and the original path is kept.
If a path does not exist or is unreadable, a warning is logged.
@warning This function must not be used when populating manifests from the
ROS_PACKAGE_PATH environment variable. It will throw an exception when that is
attempted. Instead, use PopulateFromRosPackagePath(). */
void PopulateFromEnvironment(const std::string& environment_variable);
/** Obtains one or more paths from the ROS_PACKAGE_PATH environment variable.
Semantics are similar to PopulateFromEnvironment(), except that ROS-style
crawl termination semantics are enabled, which means that subdirectories of
already-identified packages are not searched, and neither are directories
which contain any of the following marker files:
- AMENT_IGNORE
- CATKIN_IGNORE
- COLCON_IGNORE */
void PopulateFromRosPackagePath();
///@}
/** @name Functions for modifying packages already in the map */
///@{
/** Returns the deprecation message for package `package_name` if it has been
set as deprecated. A value of std::nullopt implies no deprecation. Aborts if
no package named `package_name` exists in this PackageMap. */
std::optional<std::string> GetDeprecated(
const std::string& package_name) const;
/** Sets or clears the deprecation message for package `package_name`. A
`deprecated_message` value of std::nullopt implies no deprecation. Aborts if
no package named `package_name` exists in this PackageMap. */
void SetDeprecated(const std::string& package_name,
std::optional<std::string> deprecated_message);
/** Removes package `package_name` and its previously added path. Throws if
`package_name` is not present in this PackageMap. */
void Remove(const std::string& package_name);
///@}
friend std::ostream& operator<<(std::ostream& out,
const PackageMap& package_map);
private:
/* A constructor that creates an empty map . */
explicit PackageMap(std::nullopt_t);
/* Recursively crawls through `path` looking for package.xml files. Adds the
packages defined by these package.xml files to this PackageMap.
@param[in] stop_at_package When passed true, do not crawl into subdirectories
of packages which have already been found.
@param[in] stop_markers When a directory contains one or more files or
directories with one of the given names, do not crawl into that directory or
any subdirectories when searching for packages. */
void CrawlForPackages(const std::string& path, bool stop_at_package = false,
const std::vector<std::string_view>& stop_markers = {});
/* Our member data is forward declared to hide implementation details. */
class Impl;
std::unique_ptr<Impl> impl_;
};
} // namespace multibody
} // namespace drake
// TODO(jwnimmer-tri) Add a real formatter and deprecate the operator<<.
namespace fmt {
template <>
struct formatter<drake::multibody::PackageMap> : drake::ostream_formatter {};
} // namespace fmt