From b645a0c4b14b39ed9706f96e93c7fc41d569dbe1 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 7 Aug 2024 09:36:46 -0400 Subject: [PATCH] new command geturl --- doc/src/geturl.rst | 72 +++++++++++++++++++++++ src/EXTRA-COMMAND/geturl.cpp | 111 +++++++++++++++++++++++++++++++++++ src/EXTRA-COMMAND/geturl.h | 34 +++++++++++ 3 files changed, 217 insertions(+) create mode 100644 doc/src/geturl.rst create mode 100644 src/EXTRA-COMMAND/geturl.cpp create mode 100644 src/EXTRA-COMMAND/geturl.h diff --git a/doc/src/geturl.rst b/doc/src/geturl.rst new file mode 100644 index 0000000000..e75e5cd1bf --- /dev/null +++ b/doc/src/geturl.rst @@ -0,0 +1,72 @@ +.. index:: geturl + +geturl command +============== + +Syntax +"""""" + +.. code-block:: LAMMPS + + geturl url keyword args ... + +* url = URL of the file to download +* zero or more keyword argument pairs may be provided +* keyword = *output* or *verify* or *overwrite* + + .. parsed-literal:: + + *output* filename = write to *filename* instead of inferring the name from the URL + *verify* yes/no = verify SSL certificate and hostname if *yes*, do not if *no* + *overwrite* yes/no = if *yes* overwrite the output file in case it exists, do not if *no* + +Examples +"""""""" + +.. code-block:: LAMMPS + + geturl https://www.ctcms.nist.gov/potentials/Download/1990--Ackland-G-J-Vitek-V--Cu/2/Cu2.eam.fs + geturl https://github.com/lammps/lammps/blob/develop/bench/in.lj output in.bench-lj + +Description +""""""""""" + +Download a file from an URL to the local disk. This is implemented with +the `libcurl library `_ which supports a +large variety of protocols including "http", "https", "ftp", "scp", +"sftp", "file". The transfer will only be performed on MPI rank 0. + +The *output* keyword can be used to set the filename. By default, the last part +of the URL is used. + +The *verify* keyword allows to turn on or off whether ``libcurl`` will validate +the SSL certificate and hostname for encrypted connections. Turning this off +may be required when using a proxy or connecting to a server with a self-signed +SSL certificate. + +The *overwrite* keyword determines whether a file should be overwritten if it +already exists. If the argument is *no*, then the download will be skipped +if the file exists. + +---------- + +Restrictions +"""""""""""" + +This command is part of the EXTRA-COMMAND package. It is only enabled +if LAMMPS was built with that package. See the :doc:`Build package +` page for more info. It also requires that LAMMPS was +built with support for `the libcurl library +`_. See the page about :ref:`Compiling LAMMPS +with libcurl support ` for further info. If support for +libcurl is not included, using *geturl* will trigger an error. + +Related commands +"""""""""""""""" + +:doc:`shell ` + +Default +""""""" + +*verify* = yes, *overwrite* = yes diff --git a/src/EXTRA-COMMAND/geturl.cpp b/src/EXTRA-COMMAND/geturl.cpp new file mode 100644 index 0000000000..df46d0b723 --- /dev/null +++ b/src/EXTRA-COMMAND/geturl.cpp @@ -0,0 +1,111 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + LAMMPS development team: developers@lammps.org + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing authors: Axel Kohlmeyer (Temple U), +------------------------------------------------------------------------- */ + +#include "geturl.h" + +#include "comm.h" +#include "error.h" + +#if defined(LAMMPS_CURL) +#include +#endif + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +void GetURL::command(int narg, char **arg) +{ +#if !defined(LAMMPS_CURL) + error->all(FLERR, "LAMMPS has not been compiled with libcurl support"); +#else + if (narg < 1) utils::missing_cmd_args(FLERR, "geturl", error); + int verify = 1; + int overwrite = 1; + + // process arguments + + std::string url = arg[0]; + + // sanity check + + if ((url.find(':') == std::string::npos) || (url.find('/') == std::string::npos)) + error->all(FLERR, "URL '{}' is not a supported URL", url); + + std::string output = url.substr(url.find_last_of('/') + 1); + if (output.empty()) error->all(FLERR, "URL '{}' must end in a file string", url); + + int iarg = 1; + while (iarg < narg) { + if (strcmp(arg[iarg], "output") == 0) { + if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "geturl output", error); + output = arg[iarg + 1]; + ++iarg; + } else if (strcmp(arg[iarg], "overwrite") == 0) { + if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "geturl overwrite", error); + overwrite = utils::logical(FLERR, arg[iarg + 1], false, lmp); + ++iarg; + } else if (strcmp(arg[iarg], "verify") == 0) { + if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "geturl verify", error); + verify = utils::logical(FLERR, arg[iarg + 1], false, lmp); + ++iarg; + } else { + error->all(FLERR, "Unknown geturl keyword: {}", arg[iarg]); + } + ++iarg; + } + + // only download files from rank 0 + + if (comm->me != 0) return; + + if (!overwrite && platform::file_is_readable(output)) return; + + // open output file for writing + + FILE *out = fopen(output.c_str(), "wb"); + if (!out) + error->all(FLERR, "Cannot open output file {} for writing: {}", output, utils::getsyserror()); + + // initialize curl and perform download + + CURL *curl; + curl_global_init(CURL_GLOBAL_DEFAULT); + curl = curl_easy_init(); + if (curl) { + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) out); + curl_easy_setopt(curl, CURLOPT_FILETIME, 1L); + curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); + + if (!verify) { + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + } + auto res = curl_easy_perform(curl); + if (res != CURLE_OK) { + long response = 0L; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); + error->one(FLERR, "Download of {} failed with: {} {}", output, curl_easy_strerror(res), + response); + } + curl_easy_cleanup(curl); + } + curl_global_cleanup(); + fclose(out); +#endif +} diff --git a/src/EXTRA-COMMAND/geturl.h b/src/EXTRA-COMMAND/geturl.h new file mode 100644 index 0000000000..2f4cf8ccb3 --- /dev/null +++ b/src/EXTRA-COMMAND/geturl.h @@ -0,0 +1,34 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + LAMMPS development team: developers@lammps.org + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMMAND_CLASS +// clang-format off +CommandStyle(geturl,GetURL); +// clang-format on +#else + +#ifndef LMP_GETURL_H +#define LMP_GETURL_H + +#include "command.h" + +namespace LAMMPS_NS { + +class GetURL : public Command { + public: + GetURL(class LAMMPS *lmp) : Command(lmp) {}; + void command(int, char **) override; +}; +} // namespace LAMMPS_NS +#endif +#endif