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: 1 addition & 1 deletion commandLine/src/defines.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#define OFPROJECTGENERATOR_MAJOR_VERSION "0"
#define OFPROJECTGENERATOR_MINOR_VERSION "114"
#define OFPROJECTGENERATOR_MINOR_VERSION "115"
#define OFPROJECTGENERATOR_PATCH_VERSION "0"

#define PG_VERSION (OFPROJECTGENERATOR_MAJOR_VERSION "." OFPROJECTGENERATOR_MINOR_VERSION "." OFPROJECTGENERATOR_PATCH_VERSION)
Expand Down
45 changes: 26 additions & 19 deletions commandLine/src/projects/baseProject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,16 +404,18 @@ bool baseProject::create(const fs::path & _path, string templateName){
}

bool baseProject::save(){
ofLog(OF_LOG_NOTICE) << "saving addons.make";

std::ofstream addonsMake(projectDir / "addons.make");
for (auto & a : addons) {
addonsMake << a.addonMakeName << std::endl;
// if (a.isLocalAddon) {
// addonsMake << fs::path(a.addonPath).generic_string() << std::endl;
// } else {
// addonsMake << a.name << std::endl;
// }
// no addons and no addons.make yet: don't create an empty one (#297).
// an existing one is still rewritten, so removing every addon clears it
if (addons.size() || missingAddons.size() || fs::exists(projectDir / "addons.make")) {
ofLog(OF_LOG_NOTICE) << "saving addons.make";
std::ofstream addonsMake(projectDir / "addons.make");
for (auto & a : addons) {
addonsMake << a.addonMakeName << std::endl;
}
// not found, kept so the project still says it needs them (#258)
for (auto & m : missingAddons) {
addonsMake << m << std::endl;
}
}

//save out params which the PG knows about to config.make
Expand Down Expand Up @@ -585,7 +587,11 @@ void baseProject::addAddon(const std::string & _addonName){
if(addon.load(_addonName, projectDir, target)){
addonsCache[target][addonName] = addon;
}else{
ofLogVerbose("baseProject::addAddon") << "Ignoring addon that doesn't seem to exist: " << _addonName;
// keep it in addons.make so the project still says it needs it (#258)
ofLogError("baseProject::addAddon") << "addon not found: " << ofTrim(ofSplitString(_addonName, "#")[0]) << " - kept in addons.make, install it or fix the name";
if (std::find(missingAddons.begin(), missingAddons.end(), _addonName) == missingAddons.end()) {
missingAddons.emplace_back(_addonName);
}
return; //if addon does not exist, stop early
}
}
Expand Down Expand Up @@ -646,6 +652,15 @@ void baseProject::copyAddonData(ofAddon& addon){

if(fs::exists(from)){
fs::path to { dest / d };
// bin/data (and any folders in ADDON_DATA) may not exist yet (#619)
fs::path toDir { fs::is_directory(from) ? to : to.parent_path() };
if (!fs::exists(toDir)) {
try {
fs::create_directories(toDir);
} catch (const std::exception& e) {
ofLogWarning() << "Can not create addon data folder: " << toDir.string() << " :: " << e.what();
}
}
if (fs::is_regular_file(from)){
try {
fs::copy_file(from, to, fs::copy_options::overwrite_existing); // this is addon files
Expand All @@ -655,14 +670,6 @@ void baseProject::copyAddonData(ofAddon& addon){
}

} else if (fs::is_directory(from)) {
if (!fs::exists(to)) {
try {
fs::create_directory(to);
} catch (const std::exception& e) {
std::cerr << "Error creating directories: " << e.what() << std::endl;
}
}

try {
fs::copy(from, to, fs::copy_options::overwrite_existing | fs::copy_options::recursive);
ofLogVerbose() << "adding addon data file: " << d << endl;
Expand Down
1 change: 1 addition & 0 deletions commandLine/src/projects/baseProject.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ class baseProject {
std::vector<ofAddon> addons;
std::vector<fs::path> extSrcPaths;
std::vector<std::string> projectDefines; // also written to config.make PROJECT_DEFINES for make builds
std::vector<std::string> missingAddons; // not found, still written to addons.make (#258)
std::string emscriptenWasmOption; // from the CLI, empty = keep
std::string emscriptenWasm; // value for this project: "", "32" or "64"
void saveCMakeLists();
Expand Down
7 changes: 6 additions & 1 deletion commandLine/src/projects/xcodeProject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1100,7 +1100,12 @@ bool xcodeProject::saveProjectFile() {
// alert ("emplace back " + cols[3] , 32);
// the same define / -D -U -I flag from an addon parsed twice is added once
// (not other flags: "-framework A -framework B" are separate values)
string value { cols[3] };
// the whole value, not just its first word: "src/sub folder" (#303)
string value { c.substr(cols[0].size() + cols[1].size() + cols[2].size() + 3) };
// Xcode splits build settings on spaces, quote like Xcode does for paths with spaces
if (value.find(' ') != string::npos && value.front() != '"') {
value = "\"" + value + "\"";
}
bool bUnique { key == "GCC_PREPROCESSOR_DEFINITIONS" || (bFlags && key != "OTHER_LDFLAGS" && value.size() > 2 && value[0] == '-' && (value[1] == 'D' || value[1] == 'U' || value[1] == 'I')) };
if (!bUnique || std::find(j[p].begin(), j[p].end(), value) == j[p].end()) {
j[p].emplace_back(value);
Expand Down
84 changes: 81 additions & 3 deletions frontend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ let isOfPathGood = false;
let isFirstTimeSierra = false;
let bVerbose = false;
let localAddons = [];
// addons.make lines whose addon isn't installed: kept on generate / update, shown under the addons (#258)
let missingAddons = [];
let missingAddonCloning = false;

let numAddedSrcPaths = 1;

Expand Down Expand Up @@ -98,6 +101,8 @@ ipcRenderer.on('setTranslations', (event, data) => {

//-------------------------------------------
ipcRenderer.on('setOfPath', (event, arg) => {
// picked with the folder dialog: keep it over the detected path from now on (#602)
defaultSettings.ofPathManual = true;
setOFPath(arg);
});

Expand Down Expand Up @@ -414,11 +419,14 @@ ipcRenderer.on('selectAddons', (event, arg) => {

const neededAddons = [];
localAddons = [];
missingAddons = [];

//haystack.indexOf(needle) >= 0

for (let i = 0; i < arg.length; i++) {
arg[i] = arg[i].trim();
// addons.make line, optionally "name #url"
const line = arg[i].trim();
arg[i] = line.split('#')[0].trim();
// first, check if it's already picked, then do nothing
if (addonsAlreadyPicked.indexOf(arg[i]) >= 0){
console.log("already picked"); // alread picked
Expand All @@ -435,6 +443,8 @@ ipcRenderer.on('selectAddons', (event, arg) => {
localAddons.push(arg[i]);
} else {
neededAddons.push(arg[i]);
const url = ((line.split('#')[1] || '').match(/(https?:\/\/|git@)\S+/) || [''])[0];
missingAddons.push({ name: arg[i], line, url });
}
}
}
Expand All @@ -453,6 +463,7 @@ ipcRenderer.on('selectAddons', (event, arg) => {

// $("#generate-mode-section").removeClass("has-missing-addons");
}
renderMissingAddons();

if (localAddons.length > 0){
// $("#generate-mode-section").addClass("has-missing-addons");
Expand Down Expand Up @@ -658,7 +669,7 @@ function setup() {

$('#ofPathButton').click(() => {
disableButtonTemporarily($("#ofPathButton"));
getOFPath();
getOFPath(true);
});

console.log("App is translocated: " + isFirstTimeSierra);
Expand Down Expand Up @@ -847,6 +858,11 @@ function setup() {
}
});

// typed by the user (setOFPath only triggers change)
$("#ofPath").on("input", () => {
defaultSettings.ofPathManual = true;
});

$("#ofPath").on("change", () => {
const ofpath = $("#ofPath").val();
defaultSettings.defaultOfPath = ofpath;
Expand Down Expand Up @@ -1202,6 +1218,10 @@ function generate() {
for(let i = 0; i < localAddons.length; i++) {
addonValueArray.push(localAddons[i]);
}
// and the missing ones, so they stay in addons.make (with their #url comment)
for (const m of missingAddons) {
addonValueArray.push(m.line.includes(',') ? m.name : m.line);
}

// extra source locations
const srcExtraArr = [];
Expand Down Expand Up @@ -1342,6 +1362,8 @@ function switchGenerateMode(mode) {
$("#folderButton").show();
$("#missingAddonMessage").hide();
$("#localAddonMessage").hide();
missingAddons = [];
renderMissingAddons();
$("#nameRandomiser").hide();
$("#revealProjectFiles").show();
$("#extraContainer").hide();
Expand All @@ -1366,6 +1388,8 @@ function switchGenerateMode(mode) {
$("#folderButton").show();
$("#missingAddonMessage").hide();
$("#localAddonMessage").hide();
missingAddons = [];
renderMissingAddons();
$("#nameRandomiser").show();
$("#revealProjectFiles").hide();
$("#extraContainer").hide();
Expand Down Expand Up @@ -1646,6 +1670,34 @@ function rescanAddons() {
ipcRenderer.send('isOFProjectFolder', projectInfo); // <- this forces addon reload
}

// one line per missing addon under the addons dropdown: clone it from its addons.make #url, or search for it
function renderMissingAddons() {
const $list = $('#missingAddonsField').empty();
for (const m of missingAddons) {
const $row = $('<div class="missing-addon">').append(
$('<i class="red exclamation triangle icon">'),
$('<span class="monospace">').text(m.name),
' ', $('<span>').text(t('addon.missing')), ' ');
if (m.url) {
$row.append($('<a href="#">').text(t('addon.missingDownload')).attr('title', m.url).on('click', (e) => {
e.preventDefault();
missingAddonCloning = true;
openConsoleForOperation();
// package manager style url@commit (an @ before the first / is git@host)
const at = m.url.lastIndexOf('@');
const [url, ref] = at > m.url.indexOf('/') && m.url.includes('/') ? [m.url.slice(0, at), m.url.slice(at + 1)] : [m.url, ''];
ipcRenderer.send('cloneAddon', { ofPath: $("#ofPath").val(), url, ref });
}), ' · ');
}
$row.append($('<a href="#">').text(t('addon.missingFind')).on('click', (e) => {
e.preventDefault();
ipcRenderer.send('openExternal', 'https://github.com/search?type=repositories&q=' + encodeURIComponent(m.name));
}));
$list.append($row);
}
$list.toggle(missingAddons.length > 0);
}

function cloneAddonFromGit(){
const raw = $("#addonGitUrl").val().trim();
if (raw === '') return;
Expand All @@ -1658,6 +1710,11 @@ function cloneAddonFromGit(){

ipcRenderer.on('cloneAddonDone', () => {
$("#addonGitUrl").prop('disabled', false).attr('placeholder', 'git URL, optionally url#branch-or-commit...');
// re-import the project so a downloaded missing addon gets picked
if (missingAddonCloning) {
missingAddonCloning = false;
rescanAddons();
}
});

function getRandomSketchName(){
Expand Down Expand Up @@ -1985,14 +2042,35 @@ function getOFPlatform() {
ipcRenderer.send('getHostType');
}

function getOFPath() {
// the ofPath button re-detects even over a manually set path
let ofPathDetectForced = false;

function getOFPath(force = false) {
console.log('getOFPath:sending');
ofPathDetectForced = force;
ipcRenderer.send('getOFPath');
}

// absolute folder with libs/openFrameworks and addons ("../../.." = the cmdline didn't find one)
function isOFPath(p) {
return !!p && path.isAbsolute(p)
&& fs.existsSync(path.join(p, 'libs', 'openFrameworks')) && fs.existsSync(path.join(p, 'addons'));
}

ipcRenderer.on('ofPathResult', (event, result) => {
const forced = ofPathDetectForced;
ofPathDetectForced = false;
// a path the user set (dialog / typed) wins over detection on launch and the settings tab (#602)
if (!forced && defaultSettings.ofPathManual && isOFPath($('#ofPath').val())) {
console.log('ofPath: keeping manually set path', $('#ofPath').val());
return;
}
if (result.success && !forced && !isOFPath(result.message) && isOFPath($('#ofPath').val())) {
console.log('ofPath: detected path is not an openFrameworks folder, keeping', $('#ofPath').val());
return;
}
if (result.success) {
if (forced) defaultSettings.ofPathManual = false;
console.log('ofPath:', result.message);
document.getElementById('ofPath').textContent = result.message;
setOFPath(result.message);
Expand Down
1 change: 1 addition & 0 deletions frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@
<div class="menu " id="addonsList">
</div>
</div>
<div id="missingAddonsField" style="display: none; margin-top: 0.5em;"></div>
</div>

<div class="ui red message" id="missingAddonMessage" style="display: none">
Expand Down
8 changes: 5 additions & 3 deletions frontend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ crashReporter.start({
/**
* @typedef {{
* defaultOfPath: string,
* ofPathManual: boolean,
* advancedMode: boolean,
* defaultPlatform: string,
* showConsole: boolean,
Expand All @@ -51,6 +52,7 @@ let settings = {};
/** @type Settings */
const templateSettings = {
defaultOfPath: "",
ofPathManual: false,
emsdkPath: "",
advancedMode: false,
defaultPlatform: '',
Expand Down Expand Up @@ -321,7 +323,7 @@ function sendTranslations(webContents) {
const lang = translations[settings.language] ? settings.language : 'en';
webContents.send('setTranslations', {
lang,
strings: translations[lang],
strings: { ...translations.en, ...translations[lang] },
available: AVAILABLE_LANGUAGES.map((code) => ({ code, name: translations[code]['language.name'] })),
});
}
Expand Down Expand Up @@ -937,8 +939,8 @@ ipcMain.on('isOFProjectFolder', (event, project) => {
}
});

// remove comments
projectAddons = projectAddons.map((element) => element.split('#')[0]);
// whole lines: a missing addon's "#url" comment lets the GUI clone it (#258)
projectAddons = projectAddons.map((element) => element.trim()).filter((el) => el !== '' && el[0] !== '#');

// console.log('addons', projectAddons);

Expand Down
7 changes: 5 additions & 2 deletions frontend/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"msgBox.missingAddons.body1": "Du versuchst, ein Projekt zu aktualisieren, dem folgende Addons fehlen:",
"msgBox.missingAddons.linkText": "neu scannen",
"msgBox.missingAddons.body2Suffix": "Lade die fehlenden Addons herunter und lege sie in deinen Addon-Ordner, dann {{link}}.",
"msgBox.missingAddons.body3": "Wenn du dieses Projekt ohne diese Addons aktualisierst, könntest du dessen Einstellungen überschreiben.",
"msgBox.missingAddons.body3": "Sie bleiben in addons.make; das Projekt baut erst, wenn sie installiert sind.",
"msgBox.localAddons.header": "Lokale Addons",
"msgBox.localAddons.body1": "Du versuchst, ein Projekt zu aktualisieren, das folgende lokale Addons verwendet:",
"msgBox.localAddons.body2": "Um diese lokalen Addons zu ändern, bearbeite die Datei addons.make in diesem Projekt und importiere erneut",
Expand Down Expand Up @@ -165,5 +165,8 @@
"field.appBuild": "Build:",
"tooltip.appVersionInvalid": "Die Version darf nur Ziffern und Punkte enthalten, z. B. 1, 1.2 oder 1.2.3.",
"tooltip.appBuildInvalid": "Der Build muss eine positive ganze Zahl sein, z. B. 42.",
"note.appVersionDiffers": "{{file}} hat eine andere Version: {{value}} - die aus config.make wird verwendet."
"note.appVersionDiffers": "{{file}} hat eine andere Version: {{value}} - die aus config.make wird verwendet.",
"addon.missing": "nicht installiert - bleibt in addons.make, das Projekt baut erst, wenn es installiert ist",
"addon.missingDownload": "Herunterladen",
"addon.missingFind": "Auf GitHub suchen"
}
7 changes: 5 additions & 2 deletions frontend/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"msgBox.missingAddons.body1": "You are attempting to update a project that is missing the following addons:",
"msgBox.missingAddons.linkText": "rescan it",
"msgBox.missingAddons.body2Suffix": "Please download the missing addons and put them in your addons folder, then {{link}}.",
"msgBox.missingAddons.body3": "If you choose to update this project without these addons, you may overwrite the settings on the project.",
"msgBox.missingAddons.body3": "They stay in addons.make; the project won't build until they are installed.",
"msgBox.localAddons.header": "Local addons",
"msgBox.localAddons.body1": "You are attempting to update a project that is using the following local addons:",
"msgBox.localAddons.body2": "To alter these local addons, edit the addons.make file inside this project and reimport",
Expand Down Expand Up @@ -165,5 +165,8 @@
"field.appBuild": "Build:",
"tooltip.appVersionInvalid": "Version should be digits and dots, e.g. 1, 1.2 or 1.2.3.",
"tooltip.appBuildInvalid": "Build should be a positive whole number, e.g. 42.",
"note.appVersionDiffers": "{{file}} has a different version: {{value}} - config.make's is used."
"note.appVersionDiffers": "{{file}} has a different version: {{value}} - config.make's is used.",
"addon.missing": "not installed - kept in addons.make, the project won't build until it is",
"addon.missingDownload": "Download",
"addon.missingFind": "Find on GitHub"
}
7 changes: 5 additions & 2 deletions frontend/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"msgBox.missingAddons.body1": "Estás intentando actualizar un proyecto al que le faltan los siguientes addons:",
"msgBox.missingAddons.linkText": "volver a escanear",
"msgBox.missingAddons.body2Suffix": "Descarga los addons faltantes y colócalos en tu carpeta de addons, luego {{link}}.",
"msgBox.missingAddons.body3": "Si eliges actualizar este proyecto sin estos addons, podrías sobrescribir su configuración.",
"msgBox.missingAddons.body3": "Se mantienen en addons.make; el proyecto no compilará hasta que estén instalados.",
"msgBox.localAddons.header": "Addons locales",
"msgBox.localAddons.body1": "Estás intentando actualizar un proyecto que usa los siguientes addons locales:",
"msgBox.localAddons.body2": "Para modificar estos addons locales, edita el archivo addons.make dentro de este proyecto y vuelve a importar",
Expand Down Expand Up @@ -165,5 +165,8 @@
"field.appBuild": "Compilación:",
"tooltip.appVersionInvalid": "La versión debe contener solo dígitos y puntos, p. ej. 1, 1.2 o 1.2.3.",
"tooltip.appBuildInvalid": "La compilación debe ser un número entero positivo, p. ej. 42.",
"note.appVersionDiffers": "{{file}} tiene otra versión: {{value}} - se usa la de config.make."
"note.appVersionDiffers": "{{file}} tiene otra versión: {{value}} - se usa la de config.make.",
"addon.missing": "no instalado - se mantiene en addons.make, el proyecto no compilará hasta instalarlo",
"addon.missingDownload": "Descargar",
"addon.missingFind": "Buscar en GitHub"
}
Loading
Loading