NoTeX 1.0.0
A modern noteworthy LaTeX template
Loading...
Searching...
No Matches
installer.cpp
1
9
10#include "notex/installer.hpp"
11
12#include "notex/assets.hpp"
13#include "notex/errors.hpp"
14#include "notex/logging.hpp"
15#include "notex/manager.hpp"
16#include "notex/output.hpp"
17#include "notex/system.hpp"
18
19#include <fstream>
20#include <sstream>
21#include <system_error>
22#include <vector>
23
24namespace notex {
25
26namespace {
27
28void write_file(const std::filesystem::path& path, std::string_view content) {
29 std::filesystem::create_directories(path.parent_path());
30 std::ofstream stream(path, std::ios::binary);
31 if (!stream) {
32 throw FilesystemError("could not write '" + path.string() + "'");
33 }
34 stream.write(content.data(), static_cast<std::streamsize>(content.size()));
35}
36
37std::string read_file(const std::filesystem::path& path) {
38 std::ifstream stream(path, std::ios::binary);
39 std::ostringstream buffer;
40 buffer << stream.rdbuf();
41 return buffer.str();
42}
43
47bool differs_from_embedded(const std::filesystem::path& dir,
48 const std::vector<assets::EmbeddedFile>& files) {
49 if (!std::filesystem::exists(dir)) return false;
50 for (const auto& file : files) {
51 const std::filesystem::path target = dir / file.name;
52 if (!std::filesystem::exists(target)) return true;
53 if (read_file(target) != file.content) return true;
54 }
55 return false;
56}
57
58void write_all(const std::filesystem::path& dir,
59 const std::vector<assets::EmbeddedFile>& files) {
60 std::filesystem::create_directories(dir);
61 for (const auto& file : files) {
62 write_file(dir / file.name, file.content);
63 }
64 PLOG_DEBUG << "Wrote " << files.size() << " embedded file(s) into '"
65 << dir.string() << "'.";
66}
67
71bool confirm_overwrite_if_needed(const std::filesystem::path& dir,
72 const std::vector<assets::EmbeddedFile>& files,
73 bool force) {
74 if (!differs_from_embedded(dir, files) || force) return true;
75
76 const bool confirmed = ui::confirm(
77 "A different NoTeX installation already exists at '" + dir.string() +
78 "'. Overwrite it?",
79 false);
80 if (!confirmed) {
81 PLOG_WARNING << "Installation cancelled by the user for '"
82 << dir.string() << "'.";
83 ui::warning("Installation cancelled.");
84 return false;
85 }
86 return true;
87}
88
89} // namespace
90
91bool Installer::install_global(const Environment& environment, bool force) {
92 if (!confirm_overwrite_if_needed(environment.global_latex_dir(),
93 assets::latex_files(), force) ||
94 !confirm_overwrite_if_needed(environment.global_fonts_dir(),
95 assets::font_files(), force)) {
96 return false;
97 }
98
99 write_all(environment.global_latex_dir(), assets::latex_files());
100 write_all(environment.global_fonts_dir(), assets::font_files());
101
102 try {
103 system::run_command("mktexlsr \"" + environment.texmf_home().string() +
104 "\"");
105 } catch (const NotexError& e) {
106 PLOG_WARNING << "Could not refresh the TeX filename database after "
107 "a global install: "
108 << e.what();
109 ui::warning(std::string("could not refresh the TeX filename "
110 "database: ") +
111 e.what());
112 }
113
114 return true;
115}
116
117bool Installer::install_local(const std::filesystem::path& target_dir,
118 bool force) {
119 const std::filesystem::path settings_dir = target_dir / "settings";
120 const std::filesystem::path fonts_dir = target_dir / "fonts";
121
122 if (!confirm_overwrite_if_needed(settings_dir, assets::latex_files(),
123 force) ||
124 !confirm_overwrite_if_needed(fonts_dir, assets::font_files(),
125 force)) {
126 return false;
127 }
128
129 write_all(settings_dir, assets::latex_files());
130 write_all(fonts_dir, assets::font_files());
131
132 const bool already_project =
133 std::filesystem::is_directory(target_dir / ".notex");
134 ProjectConfig config;
135 if (already_project) {
136 config = Manager(target_dir).config();
137 }
138 config.installation_type = "local";
139 Manager::write_config(target_dir, config);
140
141 return true;
142}
143
144bool Installer::uninstall_global(const Environment& environment, bool force) {
145 if (!force &&
146 !ui::confirm("Remove the NoTeX template from '" +
147 environment.global_latex_dir().string() + "' and '" +
148 environment.global_fonts_dir().string() + "'?",
149 false)) {
150 PLOG_WARNING << "Global uninstall cancelled by the user.";
151 ui::warning("Uninstall cancelled.");
152 return false;
153 }
154
155 std::error_code ec;
156 std::filesystem::remove_all(environment.global_latex_dir(), ec);
157 std::filesystem::remove_all(environment.global_fonts_dir(), ec);
158
159 try {
160 system::run_command("mktexlsr \"" + environment.texmf_home().string() +
161 "\"");
162 } catch (const NotexError& e) {
163 PLOG_WARNING << "Could not refresh the TeX filename database after "
164 "a global uninstall: "
165 << e.what();
166 ui::warning(std::string("could not refresh the TeX filename "
167 "database: ") +
168 e.what());
169 }
170
171 return true;
172}
173
174bool Installer::uninstall_local(const std::filesystem::path& target_dir,
175 bool force) {
176 if (!force &&
177 !ui::confirm("Remove the local NoTeX installation from '" +
178 (target_dir / "settings").string() + "' and '" +
179 (target_dir / "fonts").string() + "'?",
180 false)) {
181 PLOG_WARNING << "Local uninstall cancelled by the user for '"
182 << target_dir.string() << "'.";
183 ui::warning("Uninstall cancelled.");
184 return false;
185 }
186
187 std::error_code ec;
188 std::filesystem::remove_all(target_dir / "settings", ec);
189 std::filesystem::remove_all(target_dir / "fonts", ec);
190
191 if (std::filesystem::is_directory(target_dir / ".notex")) {
192 Manager manager(target_dir);
193 manager.config().installation_type.clear();
194 manager.save();
195 }
196
197 return true;
198}
199
200bool Installer::installation_differs(const std::filesystem::path& latex_dir,
201 const std::filesystem::path& fonts_dir) {
202 return differs_from_embedded(latex_dir, assets::latex_files()) ||
203 differs_from_embedded(fonts_dir, assets::font_files());
204}
205
206} // namespace notex
Accessor over the LaTeX template and font files embedded into the binary.
Represents the surrounding system as NoTeX perceives it: where TeX expects user files to live,...
const std::filesystem::path & global_fonts_dir() const noexcept
const std::filesystem::path & texmf_home() const noexcept
const std::filesystem::path & global_latex_dir() const noexcept
Raised when a filesystem operation (copy, write, remove) fails.
Definition errors.hpp:82
static bool install_local(const std::filesystem::path &target_dir, bool force=false)
Installs the template locally into target_dir.
static bool installation_differs(const std::filesystem::path &latex_dir, const std::filesystem::path &fonts_dir)
Reports whether an installation at latex_dir/fonts_dir differs from what would be freshly installed.
static bool uninstall_global(const Environment &environment, bool force=false)
Removes a global installation: every embedded LaTeX and font file's target directory inside environme...
static bool uninstall_local(const std::filesystem::path &target_dir, bool force=false)
Removes a local installation: target_dir's settings/ and fonts/ directories, then clears installation...
static bool install_global(const Environment &environment, bool force=false)
Installs the template globally, using environment to resolve the target directories inside the TeX tr...
Definition installer.cpp:91
Represents a single NoTeX project: its location and metadata.
Definition manager.hpp:74
void save() const
Persists the current metadata back to .notex/notex.json.
Definition manager.cpp:350
static void write_config(const std::filesystem::path &root_dir, const ProjectConfig &config)
Writes config as <root_dir>/.notex/notex.json, creating <root_dir>/.notex/ first if it does not alrea...
Definition manager.cpp:352
const ProjectConfig & config() const noexcept
Definition manager.hpp:105
Base class for every exception raised by the NoTeX core library.
Definition errors.hpp:43
Exception hierarchy and process exit codes used throughout NoTeX.
Installer: deploys the NoTeX LaTeX template, globally into the TeX tree or locally into a project.
Logging utility with plog initialization.
Manager: represents and operates on a single NoTeX project.
const std::vector< EmbeddedFile > & latex_files()
Definition assets.cpp:56
const std::vector< EmbeddedFile > & font_files()
Definition assets.cpp:70
std::string run_command(const std::string &command)
Runs command through the shell and returns everything it wrote to standard output (and standard error...
Definition system.cpp:19
void warning(std::string_view message)
Definition output.cpp:54
bool confirm(std::string_view prompt, bool default_answer=false)
Asks the user to confirm an action.
Definition output.cpp:68
Styled terminal output and interactive confirmation prompts.
Persisted metadata for a single NoTeX project, stored as JSON in .notex/notex.json.
Definition manager.hpp:36
std::string installation_type
Definition manager.hpp:42
Process execution and environment-variable access.