file_utils.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  * http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */
15 
16 #include <cerrno>
17 #include <cstring>
18 #include <unistd.h>
19 
20 #include <array>
21 #include <exception>
22 #include <functional>
23 #include <iostream>
24 #include <regex>
25 #include <string>
26 
27 #include <boost/date_time/c_local_time_adjustor.hpp>
28 #include <boost/date_time/posix_time/posix_time.hpp>
29 #include <boost/date_time/posix_time/posix_time_io.hpp>
30 #include <boost/date_time/local_time_adjustor.hpp>
31 #include <boost/filesystem.hpp>
32 
33 #include <aws/core/utils/logging/LogMacros.h>
35 #include <ros/ros.h>
36 #include <rosbag/bag.h>
37 #include <rosbag/view.h>
38 
40 
41 namespace
42 {
43 
44 constexpr int kMaxErrStrSize = 256;
45 constexpr char kRosBagFileFormat[] = "%Y-%m-%d-%H-%M-%S";
46 
47 }
48 
49 namespace Aws
50 {
51 namespace Rosbag
52 {
53 namespace Utils
54 {
55 
56 
57 bool ExpandAndCreateDir(const std::string & dir, std::string & expanded_dir)
58 {
59  wordexp_t wordexp_result{};
60 
61  int expand_result = wordexp_ros(dir.c_str(), &wordexp_result, 0);
62  // Directory was successfully read and expanded
63  if (0 == expand_result && 1 == wordexp_result.we_wordc) {
64  expanded_dir = *(wordexp_result.we_wordv);
65  } else {
66  std::array<char, kMaxErrStrSize> err_msg{};
67  (void) strerror_r(errno, err_msg.data(), err_msg.max_size());
68  AWS_LOGSTREAM_ERROR(__func__, "Failed to expand write directory " << expanded_dir << " with error " << err_msg.data());
69  wordfree(&wordexp_result);
70  return false;
71  }
72 
73  if (!boost::filesystem::exists(expanded_dir)) {
74  AWS_LOGSTREAM_INFO(__func__, "Provided write directory " << expanded_dir << " doesn't exist, creating.");
75  boost::filesystem::create_directories(expanded_dir);
76  if (!boost::filesystem::exists(expanded_dir)) {
77  AWS_LOGSTREAM_ERROR(__func__, "Failed to create write directory " << expanded_dir);
78  wordfree(&wordexp_result);
79  return false;
80  }
81  }
82 
83  wordfree(&wordexp_result);
84 
85  int writeable_result = access(expanded_dir.c_str(), W_OK); // test for writeability
86  if (0 != writeable_result) {
87  AWS_LOGSTREAM_WARN(__func__, "Provided write directory " << expanded_dir << " is not writeable");
88  }
89 
90  return boost::filesystem::is_directory(expanded_dir) && 0 == writeable_result;
91 }
92 
93 Aws::Rosbag::RecorderErrorCode DeleteFile(const std::string & file_path)
94 {
95  const int result = unlink(file_path.c_str());
96  if (result == 0) {
97  AWS_LOGSTREAM_INFO(__func__, "Deleted file " << file_path);
99  } else {
100  std::array<char, kMaxErrStrSize> err_msg{};
101  (void) strerror_r(errno, err_msg.data(), err_msg.max_size());
102  if (errno == ENOENT) {
103  AWS_LOGSTREAM_WARN(__func__, "Failed to delete file: " << file_path << ' ' << err_msg.data());
105  }
106  AWS_LOGSTREAM_ERROR(__func__, "Failed to delete file: " << file_path << ' ' << err_msg.data());
108  }
109 }
110 
111 boost::posix_time::time_duration GetUTCOffset() {
112  using local_adj = boost::date_time::c_local_adjustor<boost::posix_time::ptime>;
113 
114  const boost::posix_time::ptime utc_now = boost::posix_time::second_clock::universal_time();
115  const boost::posix_time::ptime now = local_adj::utc_to_local(utc_now);
116  return now - utc_now;
117 }
118 
119 ros::Time GetRosBagStartTime(const std::string& file_path)
120 {
121  // Get the file name
122  std::string file_name = file_path;
123  size_t index = file_path.find_last_of('/');
124  if (index != std::string::npos) {
125  file_name = file_path.substr(index+1);
126  }
127 
128  // Strip bag number if it exists
129  std::string bag_name = file_name;
130  index = file_path.find_last_of('_');
131  if (index != std::string::npos) {
132  bag_name = file_name.substr(0, index);
133  }
134 
135  // If bag extension wasn't stripped before, remove it now
136  std::string ts_unparsed = bag_name;
137  index = file_path.find_last_of('.');
138  if (index != std::string::npos) {
139  ts_unparsed = bag_name.substr(0, index);
140  }
141 
142  // Pull the timestamp out of the remaining string
143  std::regex time_stamp_regex(R"([0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2})");
144  std::smatch match;
145  auto ts_begin = std::sregex_iterator(ts_unparsed.begin(), ts_unparsed.end(), time_stamp_regex);
146  auto ts_end = std::sregex_iterator();
147  while (ts_begin != ts_end) {
148  match = *ts_begin;
149  ts_begin++;
150  }
151  if (match.empty()) {
152  AWS_LOGSTREAM_WARN(__func__, "Could not find timestamp in rosbag filename via regex");
153  return {};
154  }
155  std::string time_stamp = match.str(0);
156 
157  // Convert time stamp to ros time
158  auto input_facet = new boost::posix_time::time_input_facet(kRosBagFileFormat);
159  std::stringstream ss;
160  ss.imbue(std::locale(ss.getloc(), input_facet));
161  ss.str(time_stamp);
162  boost::posix_time::ptime pt;
163  ss >> pt;
164 
165  if (pt == boost::posix_time::ptime()) {
166  AWS_LOGSTREAM_WARN(__func__, "Parsing rosbag file timestamp failed");
167  return {};
168  }
169 
170  boost::posix_time::ptime utc_pt = pt - GetUTCOffset();
171 
172  try {
173  // This can throw an exception if the time is too far in the future.
174  return ros::Time::fromBoost(utc_pt);
175  } catch (std::exception& e) {
176  AWS_LOGSTREAM_WARN(__func__, "Parsing rosbag file timestamp threw exception: " << e.what());
177  return {};
178  }
179 }
180 
181 std::vector<std::string> GetRosbagsToUpload(const std::string& search_directory, const std::function<bool (rosbag::View&)>& select_file)
182 {
183  std::vector<std::string> ros_bags_to_upload;
184  using boost::filesystem::directory_iterator;
185  boost::filesystem::path ros_bag_search_path(search_directory);
186  for (auto dir_entry = directory_iterator(ros_bag_search_path); dir_entry != directory_iterator(); dir_entry++) {
187  if (boost::filesystem::is_directory(dir_entry->path())) {
188  continue;
189  }
190  if (dir_entry->path().extension().string() == ".bag") {
191  rosbag::Bag ros_bag;
192  ros_bag.open(dir_entry->path().string());
193  rosbag::View view_rosbag(ros_bag);
194  if (select_file(view_rosbag)){
195  ros_bags_to_upload.push_back(dir_entry->path().string());
196  AWS_LOG_INFO(__func__, "Adding bag: [%s] to list of bag files to upload.", dir_entry->path().string().c_str());
197  }
198  ros_bag.close();
199  }
200  }
201  return ros_bags_to_upload;
202 }
203 
204 } // namespace Utils
205 } // namespace Rosbag
206 } // namespace Aws
void open(std::string const &filename, uint32_t mode=bagmode::Read)
bool ExpandAndCreateDir(const std::string &dir, std::string &expanded_dir)
Definition: file_utils.cpp:57
ros::Time GetRosBagStartTime(const std::string &file_path)
Get the time a rosbag started.
Definition: file_utils.cpp:119
int wordexp_ros(const char *words, wordexp_t *pwordexp, int flags)
void close()
std::vector< std::string > GetRosbagsToUpload(const std::string &write_directory, const std::function< bool(rosbag::View &)> &select_file)
Definition: file_utils.cpp:181
Aws::Rosbag::RecorderErrorCode DeleteFile(const std::string &file_path)
delete a file
Definition: file_utils.cpp:93
static Time fromBoost(const boost::posix_time::ptime &t)
boost::posix_time::time_duration GetUTCOffset()
Definition: file_utils.cpp:111


rosbag_cloud_recorders
Author(s): AWS RoboMaker
autogenerated on Tue Jun 1 2021 02:51:27