28static const char *
const kShortHelp =
"usage: rootmkdir [-p|--parents] [-v|--verbose] FILE:path/to/dir [...]\n";
30Add directories in ROOT files
33 FILE:path File(s) and path(s) of directories to create
36 -h, --help get this help
37 -p, --parents create parent directories if needed, no error if directory already exists
38 -v, --verbose be verbose (can be repeated for increased verbosity)
40Note that calling rootmkdir without a directory path can be used to create files (similar to the `touch` command).
41You can also simultaneously create files and directories in it if you pass the -p flag.
44- rootmkdir example.root:dir
45 Add the directory 'dir' to the ROOT file 'example.root' (file must exists)
47- rootmkdir example.root:dir1/dir2
48 Add the directory 'dir2' in 'dir1' which exists in the ROOT file 'example.root'
50- rootmkdir -p example.root:dir1/dir2/dir3
51 Make parent directories of 'dir3' as needed, no error if target directory already exists
53- rootmkdir non_existent.root
54 Create an empty ROOT file named 'non_existent.root'
56- rootmkdir -p non_existent.root:dir1
57 Create a ROOT file named 'non_existent.root' and directory `dir1` in it
79 opts.
AddFlag({
"-p",
"--parents"});
82 opts.
Parse(args, nArgs);
85 std::cerr <<
err <<
"\n";
110 static const TClassRef dirClassRef(
"TDirectory");
112 return dirClass && dirClass->InheritsFrom(dirClassRef);
120 const auto FullPathUntil = [&tokens](
auto idx) {
121 return ROOT::Join(
"/", std::span<const std::string>{tokens.data(), idx + 1});
124 for (
auto tokIdx = 0u; tokIdx < tokens.size() - 1; ++tokIdx) {
125 TKey *existing =
dir->GetKey(tokens[tokIdx].c_str());
133 Err() <<
"error adding '" + std::string(dirPath) +
"': path '" + FullPathUntil(tokIdx) +
134 "' is already taken by an object of type '" + existing->
GetClassName() +
"'\n";
138 }
else if (createParents) {
139 dir =
dir->mkdir(tokens[tokIdx].c_str(),
"",
false);
141 Info(1) <<
"created directory '" <<
file.GetName() <<
':' << FullPathUntil(tokIdx) <<
"'\n";
143 Err() <<
"cannot create directory '" + std::string(dirPath) +
"': parent directory '" + FullPathUntil(tokIdx) +
144 "' does not exist. If you want to create the entire hierarchy, use the -p flag.\n";
152 const TKey *existing =
dir->GetKey(tokens[tokens.size() - 1].c_str());
155 Err() <<
"error adding '" + std::string(dirPath) +
"': path is already taken by an object of type '" +
158 }
else if (!createParents) {
159 Err() <<
"error adding '" + std::string(dirPath) +
"': a directory already exists at that path.\n";
167 auto newDir =
dir->mkdir(tokens[tokens.size() - 1].c_str(),
"",
false);
169 Info(1) <<
"created directory '" <<
file.GetName() <<
':' << std::string(dirPath) <<
"'\n";
171 return newDir !=
nullptr;
176 if (path.rfind(
';') != std::string_view::npos) {
177 Err() <<
"cannot specify cycle for the directory to create.\n";
188 auto args =
ParseArgs(
const_cast<const char **
>(argv) + 1, argc - 1);
199 std::vector<std::pair<std::string_view, std::string_view>> dstFilesAndPaths;
200 dstFilesAndPaths.reserve(args.fDstFileAndPaths.size());
201 for (
const auto &src : args.fDstFileAndPaths) {
204 Err() << res.GetError()->GetReport() <<
"\n";
207 auto fnameAndPath = res.Unwrap();
210 dstFilesAndPaths.push_back(fnameAndPath);
215 for (
const auto &[dstFname, dstPath] : dstFilesAndPaths) {
216 const std::string fname{dstFname};
221 if (!fileExists && !(dstPath.empty() || args.fCreateParents)) {
222 Err() <<
"cannot create directory '" << dstFname <<
":" << dstPath
223 <<
"': file does not exist. Use the -p flag if you want to create the file alongside the directories.\n";
226 }
else if (fileExists && dstPath.empty() && !args.fCreateParents) {
227 Err() <<
"cannot create file '" << fname <<
"': already exists.\n";
232 auto file = std::unique_ptr<TFile>(
TFile::Open(fname.c_str(),
"UPDATE"));
234 Err() <<
"failed to open '" << fname <<
"' for writing.\n";
237 }
else if (!fileExists) {
238 Info(1) <<
"created file '" << fname <<
"'\n";
241 if (!dstPath.empty())
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
std::vector< double > errors
void AddFlag(std::initializer_list< std::string_view > aliases, EFlagType type=EFlagType::kSwitch, std::string_view help="", std::uint32_t flagOpts=0)
Defines a new flag (either a switch or a flag with argument).
const std::vector< std::string > & GetErrors() const
Returns all parsing errors.
int GetSwitch(std::string_view name) const
If name refers to a previously-defined switch (i.e.
const std::vector< std::string > & GetArgs() const
Retrieves all positional arguments.
void Parse(const char **args, std::size_t nArgs)
@ kFlagAllowMultiple
Flag is allowed to appear multiple times (default: it's an error to see the same flag twice).
TClassRef is used to implement a permanent reference to a TClass object.
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Describe directory structure in memory.
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Book space in a file, create I/O buffers, to fill them, (un)compress them.
T * ReadObject()
To read an object (non deriving from TObject) from the file.
virtual const char * GetClassName() const
void SetLogVerbosity(int verbosity)
void InitLog(const char *name, int defaultVerbosity=1)
ROOT::RResult< std::pair< std::string_view, std::string_view > > SplitIntoFileNameAndPattern(std::string_view sourceRaw)
Given a string like "root://file.root:a/b/c", splits it into { "root://file.root",...
std::string Join(const std::string &sep, StringCollection_t &&strings)
Concatenate a list of strings with a separator.
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
static const char *const kShortHelp
Command line tool to open a ROOT file on a TBrowser.
static const char *const kLongHelp
static bool MakeDirectory(TFile &file, std::string_view dirPath, bool createParents)
static bool IsDirectory(const TKey &key)
static bool ValidateDirPath(std::string_view path)
static RootMkdirArgs ParseArgs(const char **args, int nArgs)
std::vector< std::string > fDstFileAndPaths