Skip to content
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
2 changes: 0 additions & 2 deletions core/base/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,9 @@ generateManual(haddMan ${CMAKE_SOURCE_DIR}/main/src/hadd-argparse.py ${CMAKE_BIN
generateManual(rootclingMan ${CMAKE_SOURCE_DIR}/core/dictgen/src/rootcling-argparse.py ${CMAKE_BINARY_DIR}/man/rootcling.1)

#---addRootPyCmdMan---------------------------------------------------------------------------
#generateManual(rootbrowseMan ${CMAKE_SOURCE_DIR}/main/python/rootbrowse.py ${CMAKE_BINARY_DIR}/man/rootbrowse.1)
#generateManual(rootcpMan ${CMAKE_SOURCE_DIR}/main/python/rootcp.py ${CMAKE_BINARY_DIR}/man/rootcp.1)
#generateManual(rootdrawtreeMan ${CMAKE_SOURCE_DIR}/main/python/rootdrawtree.py ${CMAKE_BINARY_DIR}/man/rootdrawtree.1)
#generateManual(rooteventselectorMan ${CMAKE_SOURCE_DIR}/main/python/rooteventselector.py ${CMAKE_BINARY_DIR}/man/rooteventselector.1)
#generateManual(rootlsMan ${CMAKE_SOURCE_DIR}/main/python/rootls.py ${CMAKE_BINARY_DIR}/man/rootls.1)
#generateManual(rootmkdirMan ${CMAKE_SOURCE_DIR}/main/python/rootmkdir.py ${CMAKE_BINARY_DIR}/man/rootmkdir.1)
#generateManual(rootmvMan ${CMAKE_SOURCE_DIR}/main/python/rootmv.py ${CMAKE_BINARY_DIR}/man/rootmv.1)
#generateManual(rootprintMan ${CMAKE_SOURCE_DIR}/main/python/rootprint.py ${CMAKE_BINARY_DIR}/man/rootprint.1)
Expand Down
1 change: 1 addition & 0 deletions main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ if(WIN32)
set_property(TARGET rootcling APPEND_STRING PROPERTY LINK_FLAGS " -STACK:4000000")
endif()

ROOT_EXECUTABLE(rootbrowse src/rootbrowse.cxx LIBRARIES RIO Core Rint Gui)
ROOT_EXECUTABLE(rootls src/rootls.cxx LIBRARIES RIO Tree Core Rint ROOTNTuple)

# Create aliases: rootcint, genreflex.
Expand Down
34 changes: 0 additions & 34 deletions main/python/cmdLineUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
# http://stackoverflow.com/questions/4675728/redirect-stdout-to-a-file-in-python/22434262#22434262
# Thanks J.F. Sebastian !!

from contextlib import contextmanager
import os
import sys
from time import sleep

Check failure on line 19 in main/python/cmdLineUtils.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (F401)

main/python/cmdLineUtils.py:19:18: F401 `time.sleep` imported but unused
from itertools import zip_longest

Check failure on line 20 in main/python/cmdLineUtils.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (F401)

main/python/cmdLineUtils.py:20:23: F401 `itertools.zip_longest` imported but unused

Check failure on line 20 in main/python/cmdLineUtils.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

main/python/cmdLineUtils.py:16:1: I001 Import block is un-sorted or un-formatted

def fileno(file_or_fd):
"""
Expand Down Expand Up @@ -81,10 +81,10 @@
ROOT.PyConfig.IgnoreCommandLineOptions = True
ROOT.gROOT.GetVersion()

import argparse

Check failure on line 84 in main/python/cmdLineUtils.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E402)

main/python/cmdLineUtils.py:84:1: E402 Module level import not at top of file
import glob

Check failure on line 85 in main/python/cmdLineUtils.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E402)

main/python/cmdLineUtils.py:85:1: E402 Module level import not at top of file
import fnmatch

Check failure on line 86 in main/python/cmdLineUtils.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E402)

main/python/cmdLineUtils.py:86:1: E402 Module level import not at top of file
import logging

Check failure on line 87 in main/python/cmdLineUtils.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E402)

main/python/cmdLineUtils.py:87:1: E402 Module level import not at top of file

Check failure on line 87 in main/python/cmdLineUtils.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

main/python/cmdLineUtils.py:84:1: I001 Import block is un-sorted or un-formatted

LOG_FORMAT = "%(levelname)s: %(message)s"
logging.basicConfig(format=LOG_FORMAT)
Expand Down Expand Up @@ -334,12 +334,12 @@
Open a ROOT file (like openROOTFile) with the possibility
to change compression settings
"""
if compress != None and os.path.isfile(fileName):

Check failure on line 337 in main/python/cmdLineUtils.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E711)

main/python/cmdLineUtils.py:337:20: E711 Comparison to `None` should be `cond is not None`
logging.warning("can't change compression settings on existing file")
return None
mode = "recreate" if recreate else "update"
theFile = openROOTFile(fileName, mode)
if compress != None:

Check failure on line 342 in main/python/cmdLineUtils.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E711)

main/python/cmdLineUtils.py:342:20: E711 Comparison to `None` should be `cond is not None`
theFile.SetCompressionSettings(compress)
return theFile

Expand Down Expand Up @@ -789,40 +789,6 @@
# End of help strings
##########

##########
# ROOTBROWSE


def _openBrowser(rootFile=None):
browser = ROOT.TBrowser()
if ROOT.gSystem.InheritsFrom("TMacOSXSystem") or browser.IsWeb():
print("Press ctrl+c to exit.")
try:
while True:
if ROOT.gROOT.IsInterrupted() or ROOT.gSystem.ProcessEvents():
break
sleep(0.01)
except (KeyboardInterrupt, SystemExit):
pass
else:
input("Press enter to exit.")


def rootBrowse(fileName=None):
if fileName:
rootFile = openROOTFile(fileName)
if not rootFile:
return 1
_openBrowser(rootFile)
rootFile.Close()
else:
_openBrowser()
return 0


# End of ROOTBROWSE
##########

##########
# ROOTCP

Expand Down
55 changes: 0 additions & 55 deletions main/python/rootbrowse.py

This file was deleted.

170 changes: 170 additions & 0 deletions main/src/rootbrowse.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
// \file rootbrowse.cxx
///
/// Command line tool to open a ROOT file on a TBrowser
///
/// \author Giacomo Parolini <giacomo.parolini@cern.ch>
/// \date 2025-08-21
#include <ROOT/RLogger.hxx>

#include <TApplication.h>
#include <TBrowser.h>
#include <TError.h>
#include <TFile.h>
#include <TGFrame.h>
#include <TROOT.h>
#include <TSystem.h>

#include <chrono>
#include <cstring>
#include <iostream>
#include <memory>
#include <thread>
#include <string_view>

static const char *const kShortHelp = "usage: rootbrowse [-w WEB|-wf] <file.root>\n";
static const char *const kLongHelp = R"(
Open a ROOT file in a TBrowser

positional arguments:
FILE Input file

options:
-h, --help show this help message and exit
-w, --web WEB Configure webdisplay. For all possible values, see TROOT::SetWebDisplay():
https://root.cern/doc/latest-stable/classTROOT.html#a1749472696545b76a6b8e79769e7e773
-wf, --webOff Invoke the classic TBrowser (not the web version)

Examples:
- rootbrowse
Open a TBrowser

- rootbrowse file.root
Open the ROOT file 'file.root' in a TBrowser
)";

static ROOT::RLogChannel &RootBrowseLog()
{
static ROOT::RLogChannel channel("RootBrowse");
return channel;
}

struct RootBrowseArgs {
enum class EPrintUsage {
kNo,
kShort,
kLong
};
EPrintUsage fPrintHelp = EPrintUsage::kNo;
std::string_view fWeb;
std::string_view fFileName;
};

static RootBrowseArgs ParseArgs(const char **args, int nArgs)
{
RootBrowseArgs outArgs;
bool forcePositional = false;

for (int i = 0; i < nArgs; ++i) {
const char *arg = args[i];

if (strcmp(arg, "--") == 0) {
forcePositional = true;
continue;
}

bool isFlag = !forcePositional && arg[0] == '-';
if (isFlag) {
++arg;
// Parse long or short flag and its argument into `argStr` / `nxtArgStr`.
std::string_view argStr, nxtArgStr;
if (arg[0] == '-') {
++arg;
// long flag: may be either of the form `--web off` or `--web=off`
const char *eq = strchr(arg, '=');
if (eq) {
argStr = std::string_view(arg, eq - arg);
nxtArgStr = std::string_view(eq + 1);
} else {
argStr = std::string_view(arg);
if (i < nArgs - 1 && args[i + 1][0] != '-') {
nxtArgStr = args[i + 1];
++i;
}
}
} else {
// short flag (note that it might be more than 1 character long, like `-wf`)
argStr = std::string_view(arg);
if (i < nArgs - 1 && args[i + 1][0] != '-') {
nxtArgStr = args[i + 1];
++i;
}
}

if (argStr == "w" || argStr == "web") {
outArgs.fWeb = nxtArgStr.empty() ? "on" : nxtArgStr;
} else if (argStr == "h" || argStr == "help") {
outArgs.fPrintHelp = RootBrowseArgs::EPrintUsage::kLong;
break;
} else if (argStr == "wf" || argStr == "--webOff") {
outArgs.fWeb = "off";
}

} else if (!outArgs.fFileName.empty()) {
outArgs.fPrintHelp = RootBrowseArgs::EPrintUsage::kShort;
break;
} else {
outArgs.fFileName = arg;
}
}

return outArgs;
}

int main(int argc, char **argv)
{
auto args = ParseArgs(const_cast<const char **>(argv) + 1, argc - 1);
if (args.fPrintHelp != RootBrowseArgs::EPrintUsage::kNo) {
std::cerr << kShortHelp;
if (args.fPrintHelp == RootBrowseArgs::EPrintUsage::kLong) {
std::cerr << kLongHelp;
return 0;
}
return 1;
}

// NOTE: we need to instantiate TApplication ourselves, otherwise TBrowser
// will create a batch application that cannot show graphics.
TApplication app("rootbrowse", nullptr, nullptr);

if (!args.fWeb.empty())
gROOT->SetWebDisplay(std::string(args.fWeb).c_str());

std::unique_ptr<TFile> file;
if (!args.fFileName.empty()) {
gErrorIgnoreLevel = kError;
file = std::unique_ptr<TFile>(TFile::Open(std::string(args.fFileName).c_str(), "READ"));
if (!file || file->IsZombie()) {
R__LOG_WARNING(RootBrowseLog()) << "File " << args.fFileName << " does not exist or is unreadable.";
}
gErrorIgnoreLevel = kUnset;
}

auto browser = std::make_unique<TBrowser>();

if (gROOT->IsBatch())
return 1;

// For classic graphics: ensure rootbrowse quits when the window is closed
if (auto imp = browser->GetBrowserImp()) {
if (auto mainframe = imp->GetMainFrame()) {
mainframe->Connect("CloseWindow()", "TApplication", &app, "Terminate()");
}
}

std::cout << "Press ctrl+c to exit.\n";
while (!gROOT->IsInterrupted() && !gSystem->ProcessEvents()) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}

return 0;
}
Loading