Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Forwardport 8 to 9 2024-04-29 #418

Merged
merged 5 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,25 @@ Downloading model:
Download succeeded.
```

**Private access tokens**
Private models and worlds can be downloaded using access tokens.
Access tokens are generated on `app.gazebosim.org`. After logging in,
go to `Settings->Access Tokens`.

An access token can be used with CLI commands via the `--header` option:

```bash
$ gz fuel download -u https://fuel.gazebosim.org/1.0/openrobotics/models/ambulance --header 'Private-Token: <access_token>'
```

Or, an access token can be stored in a `~/.gz/fuel/config.yaml` file. The token is then
automatically used by the command line tool and API calls. Use the `configure` helper
tool create your `~/.gz/fuel/config.yaml` file.

```bash
$ gz fuel configure
```

**C++ Get List models**
```cpp
// Create a client (uses https://fuel.gazebosim.org by default)
Expand Down
4 changes: 0 additions & 4 deletions conf/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,3 @@ configure_file(

# Install the yaml configuration files in an unversioned location.
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/fuel${PROJECT_VERSION_MAJOR}.yaml DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/gz/)

# Install config.yaml
install (FILES config.yaml DESTINATION
${CMAKE_INSTALL_DATAROOTDIR}/gz/${GZ_DESIGNATION}${PROJECT_VERSION_MAJOR}/)
14 changes: 0 additions & 14 deletions conf/config.yaml

This file was deleted.

10 changes: 10 additions & 0 deletions include/gz/fuel_tools/WorldIdentifier.hh
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,16 @@ namespace gz::fuel_tools
/// \return World information string
public: std::string AsPrettyString(const std::string &_prefix = "") const;

/// \brief Returns the privacy setting of the world.
/// \return True if the world is private, false if the world is
/// public.
public: bool Private() const;

/// \brief Set the privacy setting of the world.
/// \param[in] _private True indicates the world is private,
/// false indicates the world is public.
public: void SetPrivate(bool _private);

/// \brief PIMPL
private: std::unique_ptr<WorldIdentifierPrivate> dataPtr;
};
Expand Down
22 changes: 14 additions & 8 deletions src/ClientConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,24 @@ ClientConfig::ClientConfig() : dataPtr(new ClientConfigPrivate)
<< "to set cache path. Please use [GZ_FUEL_CACHE_PATH] instead."
<< std::endl;
}
else
{
return;
}
}

if (!gz::common::isDirectory(gzFuelPath))
if (!gzFuelPath.empty())
{
gzerr << "[" << gzFuelPath << "] is not a directory" << std::endl;
return;
if (!gz::common::isDirectory(gzFuelPath))
gzerr << "[" << gzFuelPath << "] is not a directory" << std::endl;
else
this->SetCacheLocation(gzFuelPath);
}
this->SetCacheLocation(gzFuelPath);

std::string configYamlFile = common::joinPaths(this->CacheLocation(),
"config.yaml");
std::string configYmlFile = common::joinPaths(this->CacheLocation(),
"config.yml");
if (gz::common::exists(configYamlFile))
this->LoadConfig(configYamlFile);
else if (gz::common::exists(configYmlFile))
this->LoadConfig(configYmlFile);
}

//////////////////////////////////////////////////
Expand Down
17 changes: 16 additions & 1 deletion src/WorldIdentifier.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,12 @@ class WorldIdentifierPrivate
/// \brief World version. Valid versions start from 1, 0 means the tip.
public: unsigned int version{0};

/// \brief Path of this model in the local cache
/// \brief Path of this world in the local cache
public: std::string localPath;

/// \brief True indicates the world is private, false indicates the
/// world is public.
public: bool privacy{false};
};

//////////////////////////////////////////////////
Expand Down Expand Up @@ -229,4 +233,15 @@ std::string WorldIdentifier::AsPrettyString(const std::string &_prefix) const
<< this->Server().AsPrettyString(_prefix + " ");
return out.str();
}
//////////////////////////////////////////////////
bool WorldIdentifier::Private() const
{
return this->dataPtr->privacy;
}

//////////////////////////////////////////////////
void WorldIdentifier::SetPrivate(bool _private)
{
this->dataPtr->privacy = _private;
}
} // namespace gz::fuel_tools
6 changes: 6 additions & 0 deletions src/WorldIdentifier_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ TEST(WorldIdentifier, SetFields)
EXPECT_EQ(std::string("hello"), id.Name());
EXPECT_EQ(std::string("acai"), id.Owner());
EXPECT_EQ(6u, id.Version());

EXPECT_FALSE(id.Private());
id.SetPrivate(true);
EXPECT_TRUE(id.Private());
id.SetPrivate(false);
EXPECT_FALSE(id.Private());
}

/////////////////////////////////////////////////
Expand Down
150 changes: 149 additions & 1 deletion src/cmd/cmdfuel.rb.in
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ else
include Fiddle
end

require 'fileutils'
require 'optparse'
require 'uri'
require 'yaml'

# Constants.
LIBRARY_NAME = '@library_location@'
Expand Down Expand Up @@ -61,6 +64,7 @@ COMMANDS = { 'fuel' =>
" gz fuel [action] [options] \n"\
" \n"\
"Available Actions: \n"\
" configure Create config.yaml configuration file \n"\
" delete Delete resources \n"\
" download Download resources \n"\
" edit Edit a resource \n"\
Expand All @@ -80,6 +84,20 @@ COMMANDS = { 'fuel' =>
}

SUBCOMMANDS = {
'configure' =>
"Create `~/.gz/fuel/config.yaml` to hold Fuel server configurations. \n"\
" \n"\
" gz fuel configure [options] \n"\
" \n"\
" --defaults Use all the defaults and save. \n"\
" This will overwrite ~/.gz/fuel/config.yaml. \n"\
" --console Output to the console instead of to a file. \n"\
" -h [--help] Print this help message. \n"\
" \n"\
" --force-version <VERSION> Use a specific library version. \n"\
" \n"\
" --versions Show the available versions. \n",

'delete' =>
"Delete simulation resources \n"\
" \n"\
Expand Down Expand Up @@ -208,7 +226,9 @@ class Cmd
'pbtxt2config' => '',
'private' => '',
'onlymodels' => '0',
'onlyworlds' => '0'
'onlyworlds' => '0',
'defaults' => false,
'console' => false
}

usage = COMMANDS[args[0]]
Expand Down Expand Up @@ -276,6 +296,12 @@ class Cmd
opts.on('--onlyworlds', 'Only update worlds') do
options['onlyworlds'] = '1'
end
opts.on('--defaults', 'Use default values') do
options['defaults'] = true
end
opts.on('--console', 'Output to console') do
options['console'] = true
end
end # opt_parser do

opt_parser.parse!(args)
Expand Down Expand Up @@ -347,6 +373,12 @@ class Cmd
end # parse()

def execute(args)
# Graceful exit on ctrl-c
Signal.trap("SIGINT") do
puts "\nExiting"
exit
end

options = parse(args)

# Read the plugin that handles the command.
Expand Down Expand Up @@ -394,6 +426,8 @@ class Cmd
end

case options['subcommand']
when 'configure'
configure(options['defaults'], options['console'])
when 'delete'
Importer.extern 'int deleteUrl(const char *, const char *)'
if not Importer.deleteUrl(options['url'], options['header'])
Expand Down Expand Up @@ -463,4 +497,118 @@ class Cmd
"from #{plugin}."
end # begin
end # execute

# Runs `gz fuel configure`
def configure(defaults, console)
# Default fuel directory and configuration path
local_fuel_dir = File.join(Dir.home, '.gz', 'fuel')
config_path = File.join(local_fuel_dir, 'config.yaml')

# The default Fuel server URL
default_url = 'https://fuel.gazebosim.org'

# A lambda function that prompts the user to enter Fuel server information
get_server_info = lambda {
server_url = default_url
default_name = 'Fuel'

# Prompt the user for a server name with a default value
# Repeat until the URL is valid, or the user hits ctrl-c
until defaults
print "Fuel server URL [#{default_url}]: "
server_url = STDIN.gets.chomp
server_url = default_url if server_url.empty?
begin
uri = URI.parse(server_url)
default_name = !uri.host || uri.host.empty? ? uri.to_s : uri.host
break
rescue URI::InvalidURIError
puts 'Invalid URL.\n'
end
end

# Prompt the user for an access token with a default value of an
# empty string
access_token = ''
unless defaults
print 'Optional access token [None]: '
access_token = STDIN.gets.chomp
end

# Get the cache location
cache = local_fuel_dir
unless defaults
print "Local cache path [#{local_fuel_dir}]: "
cache = STDIN.gets.chomp
cache = local_fuel_dir if cache.empty?
end

# Get a name to associate with this server
server_name = default_name
unless defaults
print "Name this server [#{default_name}]: "
server_name = STDIN.gets.chomp
server_name = default_name if server_name.empty?
end

[server_name, server_url, access_token, cache]
}

unless console
puts '# Set Fuel server configurations.'
puts "# This will create or replace `#{config_path}`.\n\n"
end

servers = []
confirmation = 'n'
# Allow the user to enter multiple Fuel servers
begin
server_name, server_url, access_token, cache = get_server_info.call
servers << { 'name' => server_name,
'url' => server_url,
'private-token' => access_token,
'cache' => { 'path' => cache } }
unless defaults
print "\nAdd another Fuel server? [y/N]:"
confirmation = STDIN.gets.chomp.downcase
confirmation = 'n' if confirmation.empty?
end
end while confirmation == 'y'

unless defaults || console
puts "\nReview:\n"
servers.each do |server|
puts " Name: #{server['name']}"
puts " URL: #{server['url']}"
puts " Cache: #{server['cache']['path']}"
puts " Access token: #{server['private-token']}"
puts "\n" if servers.size > 1
end
end

confirmation = 'y'
unless defaults || console
print 'Save? [Y/n]:'
confirmation = STDIN.gets.chomp.downcase
confirmation = 'y' if confirmation.empty?
end

# Save settings
if confirmation == 'y'
config = {'servers' => servers}

if console
puts config.to_yaml
else
# Make sure the ~/.gz/fuel directory exists.
FileUtils.mkdir_p(local_fuel_dir)

# Write to the config.yaml file
File.open(config_path, 'w') { |file| file.write(config.to_yaml) }
puts 'Settings saved to ~/.gz/fuel/config.yaml.'
end
else
puts 'Settings not saved.'
end
end
end # class
21 changes: 19 additions & 2 deletions src/gz_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,9 @@ TEST(CmdLine, GZ_UTILS_TEST_ENABLED_ONLY_ON_LINUX(ListFail))
TEST(CmdLine,
GZ_UTILS_TEST_ENABLED_ONLY_ON_LINUX(ModelListConfigServerUgly))
{
auto output = custom_exec_str(g_listCmd + " -t model --raw");
EXPECT_NE(output.find("https://fuel.gazebosim.org/1.0/"),
auto output = custom_exec_str(g_listCmd +
" -t model --raw -u 'https://fuel.gazebosim.org' -o openrobotics");
EXPECT_NE(output.find("https://fuel.gazebosim.org"),
std::string::npos) << output;
EXPECT_EQ(output.find("owners"), std::string::npos) << output;
}
Expand Down Expand Up @@ -151,3 +152,19 @@ TEST(CmdLine,
EXPECT_NE(output.find("owners"), std::string::npos) << output;
EXPECT_NE(output.find("worlds"), std::string::npos) << output;
}

TEST(CmdLine,
GZ_UTILS_TEST_ENABLED_ONLY_ON_LINUX(ConfigureDefaultsConsole))
{
std::string output = custom_exec_str(
g_exec + " fuel configure --console --defaults");

std::string expected =
"---\n"
"servers:\n"
"- name: Fuel\n"
" url: https://fuel.gazebosim.org\n"
" private-token: ''\n";

EXPECT_EQ(output.find(expected), 0);
}
3 changes: 2 additions & 1 deletion src/gz_src_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ TEST_F(CmdLine, ModelListFail)
// https://github.com/gazebosim/gz-fuel-tools/issues/105
TEST_F(CmdLine, ModelListConfigServerUgly)
{
EXPECT_TRUE(listModels("", "openroboticstest", "true"));
EXPECT_TRUE(listModels("https://fuel.gazebosim.org",
"openroboticstest", "true"));

EXPECT_NE(this->stdOutBuffer.str().find("https://fuel.gazebosim.org"),
std::string::npos) << this->stdOutBuffer.str();
Expand Down
Loading