diff --git a/common/jobs/job.cpp b/common/jobs/job.cpp index 8fe0b66830..35cdb19bf9 100644 --- a/common/jobs/job.cpp +++ b/common/jobs/job.cpp @@ -20,6 +20,7 @@ #include <jobs/job.h> #include <wx/filename.h> +#include <common.h> JOB::JOB( const std::string& aType, bool aOutputIsDirectory ) : m_type( aType ), @@ -94,14 +95,15 @@ void PrependDirectoryToPath( wxFileName& aFileName, const wxString aDirPath ) } -wxString JOB::GetFullOutputPath() const +wxString JOB::GetFullOutputPath( PROJECT* aProject ) const { + wxString outPath = ExpandTextVars( m_outputPath, aProject ); if( !m_tempOutputDirectory.IsEmpty() ) { if( m_outputPathIsDirectory ) { - wxFileName fn( m_outputPath ); - if( fn.IsAbsolute() || m_outputPath.IsEmpty() ) + wxFileName fn( outPath ); + if( fn.IsAbsolute() || outPath.IsEmpty() ) { fn.AssignDir( m_tempOutputDirectory ); } @@ -115,7 +117,7 @@ wxString JOB::GetFullOutputPath() const } else { - wxFileName fn( m_outputPath ); + wxFileName fn( outPath ); if( fn.IsAbsolute() ) { // uhhh, do nothing diff --git a/common/jobs/job.h b/common/jobs/job.h index dbf9065cbb..d3ca28c232 100644 --- a/common/jobs/job.h +++ b/common/jobs/job.h @@ -27,6 +27,8 @@ #include <lseq.h> #include <lset.h> +class PROJECT; + class KICOMMON_API JOB_PARAM_BASE { public: @@ -207,7 +209,7 @@ public: void SetOutputPath( const wxString& aPath ); wxString GetOutputPath() const { return m_outputPath; } - wxString GetFullOutputPath() const; + wxString GetFullOutputPath( PROJECT* aProject ) const; bool OutputPathFullSpecified() const; diff --git a/eeschema/eeschema_jobs_handler.cpp b/eeschema/eeschema_jobs_handler.cpp index 1d9592ad46..1dfdfb699f 100644 --- a/eeschema/eeschema_jobs_handler.cpp +++ b/eeschema/eeschema_jobs_handler.cpp @@ -333,7 +333,7 @@ int EESCHEMA_JOBS_HANDLER::JobExportPlot( JOB* aJob ) case JOB_PAGE_SIZE::PAGE_SIZE_AUTO: pageSizeSelect = PageFormatReq::PAGE_SIZE_AUTO; break; } - if( !PATHS::EnsurePathExists( aPlotJob->GetFullOutputPath() ) ) + if( !PATHS::EnsurePathExists( aPlotJob->GetFullOutputPath( &sch->Prj() ) ) ) { m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR ); return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; @@ -349,13 +349,13 @@ int EESCHEMA_JOBS_HANDLER::JobExportPlot( JOB* aJob ) plotOpts.m_PDFMetadata = aPlotJob->m_PDFMetadata; if (aPlotJob->GetOutpathIsDirectory()) { - plotOpts.m_outputDirectory = aPlotJob->GetFullOutputPath(); + plotOpts.m_outputDirectory = aPlotJob->GetFullOutputPath( &sch->Prj() ); plotOpts.m_outputFile = wxEmptyString; } else { plotOpts.m_outputDirectory = wxEmptyString; - plotOpts.m_outputFile = aPlotJob->GetFullOutputPath(); + plotOpts.m_outputFile = aPlotJob->GetFullOutputPath( &sch->Prj() ); } plotOpts.m_pageSizeSelect = pageSizeSelect; plotOpts.m_plotAll = aPlotJob->m_plotAll; @@ -469,13 +469,16 @@ int EESCHEMA_JOBS_HANDLER::JobExportNetlist( JOB* aJob ) aNetJob->SetOutputPath( fn.GetFullName() ); } - if( !PATHS::EnsurePathExists( aNetJob->GetFullOutputPath() ) ) + wxString outPath = aNetJob->GetFullOutputPath( &sch->Prj() ); + + if( !PATHS::EnsurePathExists( outPath ) ) { m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR ); return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; } - bool res = helper->WriteNetlist( aNetJob->GetFullOutputPath(), netlistOption, *m_reporter ); + bool res = helper->WriteNetlist( outPath, netlistOption, + *m_reporter ); if( !res ) return CLI::EXIT_CODES::ERR_UNKNOWN; @@ -676,7 +679,9 @@ int EESCHEMA_JOBS_HANDLER::JobExportBom( JOB* aJob ) aBomJob->SetOutputPath( fn.GetFullName() ); } - if( !PATHS::EnsurePathExists( aBomJob->GetFullOutputPath() ) ) + wxString outPath = aBomJob->GetFullOutputPath( &sch->Prj() ); + + if( !PATHS::EnsurePathExists( outPath ) ) { m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR ); return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; @@ -684,10 +689,9 @@ int EESCHEMA_JOBS_HANDLER::JobExportBom( JOB* aJob ) wxFile f; - if( !f.Open( aBomJob->GetFullOutputPath(), wxFile::write ) ) + if( !f.Open( outPath, wxFile::write ) ) { - m_reporter->Report( wxString::Format( _( "Unable to open destination '%s'" ), - aBomJob->GetFullOutputPath() ), + m_reporter->Report( wxString::Format( _( "Unable to open destination '%s'" ), outPath ), RPT_SEVERITY_ERROR ); return CLI::EXIT_CODES::ERR_INVALID_INPUT_FILE; @@ -795,13 +799,15 @@ int EESCHEMA_JOBS_HANDLER::JobExportPythonBom( JOB* aJob ) aNetJob->SetOutputPath( fn.GetFullName() ); } - if( !PATHS::EnsurePathExists( aNetJob->GetFullOutputPath() ) ) + wxString outPath = aNetJob->GetFullOutputPath( &sch->Prj() ); + + if( !PATHS::EnsurePathExists( outPath ) ) { m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR ); return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; } - bool res = xmlNetlist->WriteNetlist( aNetJob->GetFullOutputPath(), GNL_OPT_BOM, *m_reporter ); + bool res = xmlNetlist->WriteNetlist( outPath, GNL_OPT_BOM, *m_reporter ); if( !res ) return CLI::EXIT_CODES::ERR_UNKNOWN; @@ -1142,21 +1148,21 @@ int EESCHEMA_JOBS_HANDLER::JobSchErc( JOB* aJob ) bool wroteReport = false; + wxString outPath = ercJob->GetFullOutputPath( &sch->Prj() ); + if( ercJob->m_format == JOB_SCH_ERC::OUTPUT_FORMAT::JSON ) - wroteReport = reportWriter.WriteJsonReport( ercJob->GetFullOutputPath() ); + wroteReport = reportWriter.WriteJsonReport( outPath ); else - wroteReport = reportWriter.WriteTextReport( ercJob->GetFullOutputPath() ); + wroteReport = reportWriter.WriteTextReport( outPath ); if( !wroteReport ) { - m_reporter->Report( wxString::Format( _( "Unable to save ERC report to %s\n" ), - ercJob->GetFullOutputPath() ), + m_reporter->Report( wxString::Format( _( "Unable to save ERC report to %s\n" ), outPath ), RPT_SEVERITY_INFO ); return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; } - m_reporter->Report( - wxString::Format( _( "Saved ERC Report to %s\n" ), ercJob->GetFullOutputPath() ), + m_reporter->Report( wxString::Format( _( "Saved ERC Report to %s\n" ), outPath ), RPT_SEVERITY_INFO ); if( ercJob->m_exitCodeViolations ) diff --git a/kicad/jobs_runner.cpp b/kicad/jobs_runner.cpp index 56392a2683..c4a7c531d2 100644 --- a/kicad/jobs_runner.cpp +++ b/kicad/jobs_runner.cpp @@ -82,7 +82,7 @@ int JOBS_RUNNER::runSpecialExecute( const JOBSET_JOB* aJob, PROJECT* aProject ) specialJob->SetOutputPath( fn.GetFullPath() ); } - wxFFileOutputStream procOutput( specialJob->GetFullOutputPath() ); + wxFFileOutputStream procOutput( specialJob->GetFullOutputPath( aProject ) ); if( !procOutput.IsOk() ) return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; @@ -117,7 +117,7 @@ int JOBS_RUNNER::runSpecialCopyFiles( const JOBSET_JOB* aJob, PROJECT* aProject wxFileName sourceFn( source ); sourceFn.MakeAbsolute( projectPath ); - wxFileName destFn( job->GetFullOutputPath() ); + wxFileName destFn( job->GetFullOutputPath( aProject ) ); if( !job->m_dest.IsEmpty() ) destFn.AppendDir( job->m_dest ); diff --git a/pcbnew/pcbnew_jobs_handler.cpp b/pcbnew/pcbnew_jobs_handler.cpp index c2f25c87e5..9762536687 100644 --- a/pcbnew/pcbnew_jobs_handler.cpp +++ b/pcbnew/pcbnew_jobs_handler.cpp @@ -362,6 +362,14 @@ int PCBNEW_JOBS_HANDLER::JobExportStep( JOB* aJob ) aStepJob->SetOutputPath( fn.GetFullName() ); } + wxString outPath = aStepJob->GetFullOutputPath( brd->GetProject() ); + + if( !PATHS::EnsurePathExists( outPath ) ) + { + m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR ); + return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; + } + if( aStepJob->m_format == JOB_EXPORT_PCB_3D::FORMAT::VRML ) { @@ -388,15 +396,14 @@ int PCBNEW_JOBS_HANDLER::JobExportStep( JOB* aJob ) } bool success = vrmlExporter.ExportVRML_File( - brd->GetProject(), &messages, aStepJob->GetFullOutputPath(), scale, + brd->GetProject(), &messages, outPath, scale, aStepJob->m_3dparams.m_IncludeUnspecified, aStepJob->m_3dparams.m_IncludeDNP, !aStepJob->m_vrmlModelDir.IsEmpty(), aStepJob->m_vrmlRelativePaths, aStepJob->m_vrmlModelDir, originX, originY ); if ( success ) { - m_reporter->Report( wxString::Format( _( "Successfully exported VRML to %s" ), - aStepJob->GetFullOutputPath() ), + m_reporter->Report( wxString::Format( _( "Successfully exported VRML to %s" ), outPath ), RPT_SEVERITY_INFO ); } else @@ -435,7 +442,7 @@ int PCBNEW_JOBS_HANDLER::JobExportStep( JOB* aJob ) } EXPORTER_STEP stepExporter( brd, params ); - stepExporter.m_outputFile = aStepJob->GetFullOutputPath(); + stepExporter.m_outputFile = aStepJob->GetFullOutputPath( brd->GetProject() ); if( !stepExporter.Export() ) return CLI::EXIT_CODES::ERR_UNKNOWN; @@ -667,7 +674,7 @@ int PCBNEW_JOBS_HANDLER::JobExportRender( JOB* aJob ) image = image.Mirror( false ); image.SetOption( wxIMAGE_OPTION_QUALITY, 90 ); - image.SaveFile( aRenderJob->GetFullOutputPath(), + image.SaveFile( aRenderJob->GetFullOutputPath( brd->GetProject() ), aRenderJob->m_format == JOB_PCB_RENDER::FORMAT::PNG ? wxBITMAP_TYPE_PNG : wxBITMAP_TYPE_JPEG ); } @@ -736,7 +743,7 @@ int PCBNEW_JOBS_HANDLER::JobExportSvg( JOB* aJob ) sheetPath = aSvgJob->GetVarOverrides().at( wxT( "SHEETPATH" ) ); } - if( !plotter.Plot( aSvgJob->GetFullOutputPath(), aSvgJob->m_printMaskLayer, + if( !plotter.Plot( aSvgJob->GetFullOutputPath( brd->GetProject() ), aSvgJob->m_printMaskLayer, aSvgJob->m_printMaskLayersToIncludeOnAllLayers, false, aSvgJob->m_genMode == JOB_EXPORT_PCB_SVG::GEN_MODE::SINGLE, layerName, @@ -800,7 +807,7 @@ int PCBNEW_JOBS_HANDLER::JobExportDxf( JOB* aJob ) sheetPath = aDxfJob->GetVarOverrides().at( wxT( "SHEETPATH" ) ); } - if( !plotter.Plot( aDxfJob->GetFullOutputPath(), aDxfJob->m_printMaskLayer, + if( !plotter.Plot( aDxfJob->GetFullOutputPath( brd->GetProject() ), aDxfJob->m_printMaskLayer, aDxfJob->m_printMaskLayersToIncludeOnAllLayers, false, aDxfJob->m_genMode == JOB_EXPORT_PCB_DXF::GEN_MODE::SINGLE, layerName, sheetName, sheetPath ) ) @@ -851,7 +858,9 @@ int PCBNEW_JOBS_HANDLER::JobExportPdf( JOB* aJob ) PCB_PLOTTER pcbPlotter( brd, m_reporter, plotOpts ); - if( !PATHS::EnsurePathExists( aPdfJob->GetFullOutputPath() ) ) + wxString outPath = aPdfJob->GetFullOutputPath( brd->GetProject() ); + + if( !PATHS::EnsurePathExists( outPath ) ) { m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR ); return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; @@ -874,7 +883,7 @@ int PCBNEW_JOBS_HANDLER::JobExportPdf( JOB* aJob ) LOCALE_IO dummy; - if( !pcbPlotter.Plot( aPdfJob->GetFullOutputPath(), aPdfJob->m_printMaskLayer, + if( !pcbPlotter.Plot( outPath, aPdfJob->m_printMaskLayer, aPdfJob->m_printMaskLayersToIncludeOnAllLayers, false, aPdfJob->m_pdfGenMode == JOB_EXPORT_PCB_PDF::GEN_MODE::ALL_LAYERS_ONE_FILE, @@ -970,7 +979,7 @@ int PCBNEW_JOBS_HANDLER::JobExportGerbers( JOB* aJob ) else fileExt = FILEEXT::GerberFileExtension; - BuildPlotFileName( &fn, aGerberJob->GetFullOutputPath(), layerName, fileExt ); + BuildPlotFileName( &fn, aGerberJob->GetFullOutputPath( brd->GetProject() ), layerName, fileExt ); wxString fullname = fn.GetFullName(); jobfile_writer.AddGbrFile( layer, fullname ); @@ -1015,7 +1024,7 @@ int PCBNEW_JOBS_HANDLER::JobExportGerbers( JOB* aJob ) wxFileName fn( brd->GetFileName() ); // Build gerber job file from basename - BuildPlotFileName( &fn, aGerberJob->GetFullOutputPath(), wxT( "job" ), + BuildPlotFileName( &fn, aGerberJob->GetFullOutputPath( brd->GetProject() ), wxT( "job" ), FILEEXT::GerberJobFileExtension ); jobfile_writer.CreateJobFile( fn.GetFullPath() ); @@ -1029,15 +1038,15 @@ int PCBNEW_JOBS_HANDLER::JobExportGencad( JOB* aJob ) if( aGencadJob == nullptr ) return CLI::EXIT_CODES::ERR_UNKNOWN; - BOARD* aBoard = LoadBoard( aGencadJob->m_filename, true ); // Ensure m_board is of type BOARD* + BOARD* brd = LoadBoard( aGencadJob->m_filename, true ); // Ensure m_board is of type BOARD* - if( aBoard == nullptr ) + if( brd == nullptr ) return CLI::EXIT_CODES::ERR_UNKNOWN; - GENCAD_EXPORTER exporter( aBoard ); + GENCAD_EXPORTER exporter( brd ); VECTOR2I GencadOffset; - VECTOR2I auxOrigin = aBoard->GetDesignSettings().GetAuxOrigin(); + VECTOR2I auxOrigin = brd->GetDesignSettings().GetAuxOrigin(); GencadOffset.x = aGencadJob->m_useDrillOrigin ? auxOrigin.x : 0; GencadOffset.y = aGencadJob->m_useDrillOrigin ? auxOrigin.y : 0; @@ -1049,17 +1058,26 @@ int PCBNEW_JOBS_HANDLER::JobExportGencad( JOB* aJob ) if( aGencadJob->GetOutputPath().IsEmpty() ) { - wxFileName fn = aBoard->GetFileName(); + wxFileName fn = brd->GetFileName(); fn.SetName( fn.GetName() ); fn.SetExt( GetDefaultPlotExtension( PLOT_FORMAT::DXF ) ); aGencadJob->SetOutputPath( fn.GetFullName() ); } - if( !exporter.WriteFile( aGencadJob->GetFullOutputPath() ) ) + wxString outPath = aGencadJob->GetFullOutputPath( brd->GetProject() ); + + if( !PATHS::EnsurePathExists( outPath ) ) + { + m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR ); + return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; + } + + + if( !exporter.WriteFile( outPath ) ) { wxString msg; - msg.Printf( _( "Failed to create file '%s'.\n" ), aGencadJob->GetFullOutputPath() ); + msg.Printf( _( "Failed to create file '%s'.\n" ), outPath ); m_reporter->Report( msg, RPT_SEVERITY_ERROR ); @@ -1150,7 +1168,7 @@ int PCBNEW_JOBS_HANDLER::JobExportGerber( JOB* aJob ) // We are feeding it one layer at the start here to silence a logic check GERBER_PLOTTER* plotter = (GERBER_PLOTTER*) StartPlotBoard( brd, &plotOpts, layer, layerName, - aGerberJob->GetFullOutputPath(), + aGerberJob->GetFullOutputPath( brd->GetProject() ), sheetName, sheetPath ); if( plotter ) @@ -1161,7 +1179,7 @@ int PCBNEW_JOBS_HANDLER::JobExportGerber( JOB* aJob ) else { m_reporter->Report( wxString::Format( _( "Failed to plot to '%s'.\n" ), - aGerberJob->GetFullOutputPath() ), + aGerberJob->GetFullOutputPath( brd->GetProject() ) ), RPT_SEVERITY_ERROR ); exitCode = CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; } @@ -1187,10 +1205,10 @@ int PCBNEW_JOBS_HANDLER::JobExportDrill( JOB* aJob ) if( !brd ) return CLI::EXIT_CODES::ERR_INVALID_INPUT_FILE; - // ensure output dir exists - wxFileName fn( aDrillJob->GetFullOutputPath() + wxT( "/" ) ); - if( !fn.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) ) + wxString outPath = aDrillJob->GetFullOutputPath( brd->GetProject() ); + + if( !PATHS::EnsurePathExists( outPath ) ) { m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR ); return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; @@ -1263,7 +1281,7 @@ int PCBNEW_JOBS_HANDLER::JobExportDrill( JOB* aJob ) excellonWriter->SetRouteModeForOvalHoles( aDrillJob->m_excellonOvalDrillRoute ); excellonWriter->SetMapFileFormat( mapFormat ); - if( !excellonWriter->CreateDrillandMapFilesSet( aDrillJob->GetFullOutputPath(), true, + if( !excellonWriter->CreateDrillandMapFilesSet( outPath, true, aDrillJob->m_generateMap, m_reporter ) ) { return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; @@ -1283,7 +1301,7 @@ int PCBNEW_JOBS_HANDLER::JobExportDrill( JOB* aJob ) gerberWriter->SetOptions( offset ); gerberWriter->SetMapFileFormat( mapFormat ); - if( !gerberWriter->CreateDrillandMapFilesSet( aDrillJob->GetFullOutputPath(), true, + if( !gerberWriter->CreateDrillandMapFilesSet( outPath, true, aDrillJob->m_generateMap, m_reporter ) ) { return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; @@ -1323,11 +1341,19 @@ int PCBNEW_JOBS_HANDLER::JobExportPos( JOB* aJob ) aPosJob->SetOutputPath( fn.GetFullName() ); } + wxString outPath = aPosJob->GetFullOutputPath( brd->GetProject() ); + + if( !PATHS::EnsurePathExists( outPath ) ) + { + m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR ); + return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; + } + if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::ASCII || aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::CSV ) { FILE* file = nullptr; - file = wxFopen( aPosJob->GetFullOutputPath(), wxS( "wt" ) ); + file = wxFopen( outPath, wxS( "wt" ) ); if( file == nullptr ) return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; @@ -1353,7 +1379,7 @@ int PCBNEW_JOBS_HANDLER::JobExportPos( JOB* aJob ) fputs( data.c_str(), file ); fclose( file ); - aPosJob->AddOutput( aPosJob->GetFullOutputPath() ); + aPosJob->AddOutput( outPath ); } else if( aPosJob->m_format == JOB_EXPORT_PCB_POS::FORMAT::GERBER ) { @@ -1364,10 +1390,10 @@ int PCBNEW_JOBS_HANDLER::JobExportPos( JOB* aJob ) if( aPosJob->m_side == JOB_EXPORT_PCB_POS::SIDE::BACK ) gbrLayer = B_Cu; - if( exporter.CreatePlaceFile( aPosJob->GetFullOutputPath(), gbrLayer, aPosJob->m_gerberBoardEdge ) + if( exporter.CreatePlaceFile( outPath, gbrLayer, aPosJob->m_gerberBoardEdge ) >= 0 ) { - aPosJob->AddOutput( aPosJob->GetFullOutputPath() ); + aPosJob->AddOutput( outPath ); } else { @@ -1635,6 +1661,14 @@ int PCBNEW_JOBS_HANDLER::JobExportDrc( JOB* aJob ) drcJob->SetOutputPath( fn.GetFullName() ); } + wxString outPath = drcJob->GetFullOutputPath( brd->GetProject() ); + + if( !PATHS::EnsurePathExists( outPath ) ) + { + m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR ); + return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; + } + EDA_UNITS units; switch( drcJob->m_units ) @@ -1748,19 +1782,18 @@ int PCBNEW_JOBS_HANDLER::JobExportDrc( JOB* aJob ) bool wroteReport = false; if( drcJob->m_format == JOB_PCB_DRC::OUTPUT_FORMAT::JSON ) - wroteReport = reportWriter.WriteJsonReport( drcJob->GetFullOutputPath() ); + wroteReport = reportWriter.WriteJsonReport( outPath ); else - wroteReport = reportWriter.WriteTextReport( drcJob->GetFullOutputPath() ); + wroteReport = reportWriter.WriteTextReport( outPath ); if( !wroteReport ) { - m_reporter->Report( wxString::Format( _( "Unable to save DRC report to %s\n" ), - drcJob->GetFullOutputPath() ), + m_reporter->Report( wxString::Format( _( "Unable to save DRC report to %s\n" ), outPath ), RPT_SEVERITY_INFO ); return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; } - m_reporter->Report( wxString::Format( _( "Saved DRC Report to %s\n" ), drcJob->GetFullOutputPath() ), + m_reporter->Report( wxString::Format( _( "Saved DRC Report to %s\n" ), outPath ), RPT_SEVERITY_INFO ); if( drcJob->m_exitCodeViolations ) @@ -1797,6 +1830,15 @@ int PCBNEW_JOBS_HANDLER::JobExportIpc2581( JOB* aJob ) job->SetOutputPath( fn.GetName() ); } + wxString outPath = job->GetFullOutputPath( brd->GetProject() ); + + if( !PATHS::EnsurePathExists( outPath ) ) + { + m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR ); + return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; + } + + std::map<std::string, UTF8> props; props["units"] = job->m_units == JOB_EXPORT_PCB_IPC2581::IPC2581_UNITS::MILLIMETERS ? "mm" : "inch"; @@ -1828,7 +1870,7 @@ int PCBNEW_JOBS_HANDLER::JobExportIpc2581( JOB* aJob ) if( job->m_compress ) { - wxFileName tempfn = job->GetFullOutputPath(); + wxFileName tempfn = outPath; tempfn.SetExt( FILEEXT::Ipc2581FileExtension ); wxFileName zipfn = tempFile; zipfn.SetExt( "zip" ); @@ -1847,12 +1889,12 @@ int PCBNEW_JOBS_HANDLER::JobExportIpc2581( JOB* aJob ) } // If save succeeded, replace the original with what we just wrote - if( !wxRenameFile( tempFile, job->GetFullOutputPath() ) ) + if( !wxRenameFile( tempFile, outPath ) ) { m_reporter->Report( wxString::Format( _( "Error generating IPC2581 file '%s'.\n" "Failed to rename temporary file '%s." ) + wxS( "\n" ), - job->GetFullOutputPath(), tempFile ), + outPath, tempFile ), RPT_SEVERITY_ERROR ); }