3 #include <boost/filesystem.hpp>
4 #include <boost/program_options.hpp>
6 #include "authenticate.h"
9 #include "garage_tools_version.h"
10 #include "logging/logging.h"
11 #include "ostree_dir_repo.h"
12 #include "ostree_repo.h"
13 #include "utilities/xml2json.h"
15 namespace po = boost::program_options;
17 int main(
int argc,
char **argv) {
20 boost::filesystem::path repo_path;
22 boost::filesystem::path credentials_path;
24 boost::filesystem::path manifest_path;
25 int max_curl_requests;
27 po::options_description desc(
"garage-push command line options");
30 (
"help",
"print usage")
31 (
"version",
"Current garage-push version")
32 (
"verbose,v",
"Verbose logging (loglevel 1)")
33 (
"quiet,q",
"Quiet mode (loglevel 3)")
34 (
"loglevel", po::value<int>(),
"set log level 0-5 (trace, debug, info, warning, error, fatal)")
35 (
"repo,C", po::value<boost::filesystem::path>(&repo_path)->required(),
"location of OSTree repo")
36 (
"ref,r", po::value<std::string>(&ref)->required(),
"OSTree ref to push (or commit refhash)")
37 (
"credentials,j", po::value<boost::filesystem::path>(&credentials_path)->required(),
"credentials (json or zip containing json)")
38 (
"cacert", po::value<std::string>(&cacerts),
"override path to CA root certificates, in the same format as curl --cacert")
39 (
"repo-manifest", po::value<boost::filesystem::path>(&manifest_path),
"manifest describing repository branches used in the image, to be sent as attached metadata")
40 (
"jobs", po::value<int>(&max_curl_requests)->default_value(30),
"maximum number of parallel requests")
41 (
"dry-run,n",
"check arguments and authenticate but don't upload")
42 (
"walk-tree,w",
"walk entire tree and upload all missing objects");
48 po::store(po::parse_command_line(argc,
reinterpret_cast<const char *
const *
>(argv), desc), vm);
50 if (vm.count(
"help") != 0U) {
54 if (vm.count(
"version") != 0) {
55 LOG_INFO <<
"Current garage-push version is: " << garage_tools_version();
59 }
catch (
const po::error &o) {
60 LOG_ERROR << o.what();
67 if (vm.count(
"loglevel") != 0) {
68 const int loglevel = vm[
"loglevel"].as<
int>();
69 logger_set_threshold(
static_cast<boost::log::trivial::severity_level
>(loglevel));
70 LOG_INFO <<
"Loglevel set to " << loglevel;
71 }
else if (
static_cast<int>(vm.count(
"verbose")) != 0) {
72 logger_set_threshold(boost::log::trivial::debug);
73 LOG_DEBUG <<
"Debug level debugging enabled";
74 }
else if (
static_cast<int>(vm.count(
"quiet")) != 0) {
75 logger_set_threshold(boost::log::trivial::warning);
77 logger_set_threshold(boost::log::trivial::info);
79 }
catch (std::exception &e) {
80 LOG_FATAL << e.what();
84 Utils::setUserAgent(std::string(
"garage-push/") + garage_tools_version());
86 if (!cacerts.empty()) {
87 if (!boost::filesystem::exists(cacerts)) {
88 LOG_FATAL <<
"--cacert path " << cacerts <<
" does not exist";
93 if (vm.count(
"dry-run") != 0U) {
96 if (vm.count(
"walk-tree") != 0U) {
105 if (max_curl_requests < 1) {
106 LOG_FATAL <<
"--jobs must be greater than 0";
110 OSTreeRepo::ptr src_repo = std::make_shared<OSTreeDirRepo>(repo_path);
111 if (!src_repo->LooksValid()) {
112 LOG_FATAL <<
"The OSTree src repository does not appear to contain a valid OSTree repository";
117 std::unique_ptr<OSTreeHash> commit;
119 OSTreeRef ostree_ref = src_repo->GetRef(ref);
120 if (ostree_ref.IsValid()) {
121 commit = std_::make_unique<OSTreeHash>(ostree_ref.GetHash());
126 LOG_FATAL <<
"Ref or commit refhash " << ref <<
" was not found in repository " << repo_path.string();
134 if (authenticate(cacerts, push_credentials, push_server) != EXIT_SUCCESS) {
135 LOG_FATAL <<
"Authentication with push server failed";
138 if (!UploadToTreehub(src_repo, push_server, *commit, mode, max_curl_requests)) {
139 LOG_FATAL <<
"Upload to treehub failed";
145 if (!PushRootRef(push_server, ostree_ref)) {
146 LOG_FATAL <<
"Error pushing root ref to treehub";
150 LOG_INFO <<
"Provided ref " << ref <<
" is a commit refhash. Cannot push root ref";
154 if (!manifest_path.empty()) {
156 std::string manifest_json_str;
157 std::ifstream ifs(manifest_path.string());
158 std::stringstream ss;
159 auto manifest_json = xml2json::xml2json(ifs);
161 manifest_json_str = ss.str();
163 LOG_INFO <<
"Sending manifest:\n" << manifest_json_str;
165 CURL *curl = curl_easy_init();
166 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
167 push_server.SetContentType(
"Content-Type: application/json");
168 push_server.InjectIntoCurl(
"manifests/" + commit->string(), curl);
169 curlEasySetoptWrapper(curl, CURLOPT_CUSTOMREQUEST,
"PUT");
170 curlEasySetoptWrapper(curl, CURLOPT_POSTFIELDS, manifest_json_str.c_str());
171 CURLcode rc = curl_easy_perform(curl);
173 if (rc != CURLE_OK) {
174 LOG_ERROR <<
"Error pushing repo manifest to Treehub";
176 curl_easy_cleanup(curl);
178 }
catch (std::exception &e) {
179 LOG_ERROR <<
"Could not send repo manifest to Treehub";
183 LOG_FATAL << e.what();
186 LOG_FATAL << e.what();
189 LOG_FATAL << e.what();