From 474f1b3cc6e94ff17d9a4d123ea82dbe5ef00328 Mon Sep 17 00:00:00 2001 From: Ivor Townsend Date: Fri, 26 Nov 2021 15:06:38 +0000 Subject: [PATCH 1/3] feat: Adding Delete Folder Macro --- base/mp_deletefolder.sas | 54 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 base/mp_deletefolder.sas diff --git a/base/mp_deletefolder.sas b/base/mp_deletefolder.sas new file mode 100644 index 0000000..5bdd04c --- /dev/null +++ b/base/mp_deletefolder.sas @@ -0,0 +1,54 @@ +/** + @file + @brief A macro to delete a directory + @details Will delete all folder content (including subfolder content) and + finally, the folder itself. + + @param path Unquoted path to the folder to delete. + +

SAS Macros

+ @li mp_dirlist.sas + +**/ + +%macro mp_deletefolder(folder); + %let rc = %sysfunc(filename(fid,&folder)); + %if &rc %then %do; + %put rc = &rc ; + %put %sysfunc(sysmsg()); + %end; + %else %do; + %let rc = %sysfunc(fexist(&fid)); + %if not &rc %then %put Folder does not exist. ; + %else %if &rc %then %do; + %mp_dirlist(path=&folder,outds=mp_dirlist); + %let dsid = %sysfunc(open(mp_dirlist)); + %let nobs = %sysfunc(attrn(&dsid,nobs)); + %let rc = %sysfunc(close(&dsid)); + %if &nobs %then %do; + proc sort data=mp_dirlist; + by descending level; + run; + data _null_; + set mp_dirlist; + rc=filename('delfile',filepath); + rc=fdelete('delfile'); + if rc then do; + put 'rc = ' rc; + filepath=trim(filepath); + put 'Delete of ' filepath 'failed.'; + end; + run; + /* tidy up */ + proc sql; + drop table mp_dirlist; + quit; + %end; + %let rc=%sysfunc(fdelete(&fid)); + %if &rc %then %do; + %put rc = &rc; + %put %sysfunc(sysmsg()); + %end; + %end; + %end; +%mend mp_deletefolder; \ No newline at end of file From 9e84e47563f215be139c3d5cfb24e23dcdc18b13 Mon Sep 17 00:00:00 2001 From: Allan Bowe Date: Fri, 26 Nov 2021 16:20:13 +0000 Subject: [PATCH 2/3] feat: mp_deletefolder tests, closes #90 --- base/mp_deletefolder.sas | 91 ++++++++++++-------- base/mp_dirlist.sas | 5 +- tests/crossplatform/mp_deletefolder.test.sas | 50 +++++++++++ tests/crossplatform/mp_dirlist.test.sas | 4 +- 4 files changed, 109 insertions(+), 41 deletions(-) create mode 100644 tests/crossplatform/mp_deletefolder.test.sas diff --git a/base/mp_deletefolder.sas b/base/mp_deletefolder.sas index 5bdd04c..ee31d77 100644 --- a/base/mp_deletefolder.sas +++ b/base/mp_deletefolder.sas @@ -4,51 +4,66 @@ @details Will delete all folder content (including subfolder content) and finally, the folder itself. + Usage: + + %let rootdir=%sysfunc(pathname(work))/demo; + %mf_mkdir(&rootdir) + %mf_mkdir(&rootdir/subdir) + %mf_mkdir(&rootdir/subdir/subsubdir) + data "&rootdir/subdir/example.sas7bdat"; + run; + + %mp_deletefolder(&rootdir) + @param path Unquoted path to the folder to delete.

SAS Macros

+ @li mf_getuniquename.sas + @li mf_isdir.sas @li mp_dirlist.sas +

Related Macros

+ @li mp_deletefolder.test.sas + **/ %macro mp_deletefolder(folder); - %let rc = %sysfunc(filename(fid,&folder)); - %if &rc %then %do; - %put rc = &rc ; - %put %sysfunc(sysmsg()); - %end; - %else %do; - %let rc = %sysfunc(fexist(&fid)); - %if not &rc %then %put Folder does not exist. ; - %else %if &rc %then %do; - %mp_dirlist(path=&folder,outds=mp_dirlist); - %let dsid = %sysfunc(open(mp_dirlist)); - %let nobs = %sysfunc(attrn(&dsid,nobs)); - %let rc = %sysfunc(close(&dsid)); - %if &nobs %then %do; - proc sort data=mp_dirlist; - by descending level; - run; - data _null_; - set mp_dirlist; - rc=filename('delfile',filepath); - rc=fdelete('delfile'); - if rc then do; - put 'rc = ' rc; - filepath=trim(filepath); - put 'Delete of ' filepath 'failed.'; - end; - run; - /* tidy up */ - proc sql; - drop table mp_dirlist; - quit; - %end; - %let rc=%sysfunc(fdelete(&fid)); - %if &rc %then %do; - %put rc = &rc; - %put %sysfunc(sysmsg()); - %end; - %end; + /* proceed if valid directory */ + %if %mf_isdir(&folder)=1 %then %do; + + /* prep temp table */ + %local tempds; + %let tempds=%mf_getuniquename(); + + /* recursive directory listing */ + %mp_dirlist(path=&folder,outds=work.&tempds, maxdepth=MAX) + + /* sort descending level so can delete folder contents before folders */ + proc sort data=work.&tempds; + by descending level; + run; + + /* ensure top level folder is removed at the end */ + proc sql; + insert into work.&tempds set filepath="&folder"; + + /* delete everything */ + data _null_; + set work.&tempds end=last; + length fref $8; + rc=filename(fref,filepath); + rc=fdelete(fref); + if rc then do; + msg=sysmsg(); + put "&sysmacroname:" / rc= / msg= / filepath=; + end; + rc=filename(fref); + run; + + /* tidy up */ + proc sql; + drop table work.&tempds; + %end; + %else %put &sysmacroname: &folder: is not a valid / accessible folder. ; %mend mp_deletefolder; \ No newline at end of file diff --git a/base/mp_dirlist.sas b/base/mp_dirlist.sas index 23b0df5..504ec36 100644 --- a/base/mp_dirlist.sas +++ b/base/mp_dirlist.sas @@ -51,6 +51,9 @@

SAS Macros

@li mp_dropmembers.sas +

Related Macros

+ @li mp_dirlist.test.sas + @version 9.2 @author Allan Bowe **/ @@ -71,7 +74,7 @@ data;run; /* drop main (top) table if it exists */ %if &level=0 %then %do; - %mp_dropmembers(&outds, libref=WORK) + %mp_dropmembers(%scan(&outds,-1,.), libref=WORK) %end; data &out_ds(compress=no diff --git a/tests/crossplatform/mp_deletefolder.test.sas b/tests/crossplatform/mp_deletefolder.test.sas new file mode 100644 index 0000000..97135bb --- /dev/null +++ b/tests/crossplatform/mp_deletefolder.test.sas @@ -0,0 +1,50 @@ +/** + @file + @brief Testing mp_deletefolder.sas macro + +

SAS Macros

+ @li mp_deletefolder.sas + @li mf_mkdir.sas + @li mf_nobs.sas + @li mp_assert.sas + @li mp_dirlist.sas + +**/ + +/** + * make a directory structure + */ + +%let root=%sysfunc(pathname(work))/top; +%mf_mkdir(&root) +%mf_mkdir(&root/a) +%mf_mkdir(&root/b) +%mf_mkdir(&root/a/d) +%mf_mkdir(&root/a/e) +%mf_mkdir(&root/a/e/f) +data "&root/a/e/f/ds1.sas7bdat"; + x=1; +run; + +%mp_dirlist(path=&root, outds=myTable, maxdepth=MAX) + +%mp_assert( + iftrue=(%mf_nobs(work.mytable)=6), + desc=Temp data successfully created, + outds=work.test_results +) + +%mp_deletefolder(&root/a) + +%mp_dirlist(path=&root, outds=work.myTable2, maxdepth=MAX) + +data _null_; + set work.mytable2; + putlog (_all_)(=); +run; + +%mp_assert( + iftrue=(%mf_nobs(work.mytable2)=1), + desc=Subfolder and contents successfully deleted, + outds=work.test_results +) diff --git a/tests/crossplatform/mp_dirlist.test.sas b/tests/crossplatform/mp_dirlist.test.sas index ca0becc..2bec770 100644 --- a/tests/crossplatform/mp_dirlist.test.sas +++ b/tests/crossplatform/mp_dirlist.test.sas @@ -1,6 +1,6 @@ /** @file - @brief Testing mp_ds2cards.sas macro + @brief Testing mp_dirlist.sas macro

SAS Macros

@li mf_nobs.sas @@ -41,7 +41,7 @@ run; outds=work.test_results ) -%mp_dirlist(path=&root, outds=myTable3, maxdepth=0) +%mp_dirlist(path=&root, outds=work.myTable3, maxdepth=0) %mp_assert( iftrue=(%mf_nobs(work.mytable3)=2), From 3b395b3ae57e0ecd5bb89cecbe68f1a51f8d51f0 Mon Sep 17 00:00:00 2001 From: Allan Bowe Date: Fri, 26 Nov 2021 16:20:33 +0000 Subject: [PATCH 3/3] chore: all.sas update --- all.sas | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/all.sas b/all.sas index b35baee..1e8ec11 100644 --- a/all.sas +++ b/all.sas @@ -3066,6 +3066,74 @@ data &outds; run; %mend mp_deleteconstraints;/** + @file + @brief A macro to delete a directory + @details Will delete all folder content (including subfolder content) and + finally, the folder itself. + + Usage: + + %let rootdir=%sysfunc(pathname(work))/demo; + %mf_mkdir(&rootdir) + %mf_mkdir(&rootdir/subdir) + %mf_mkdir(&rootdir/subdir/subsubdir) + data "&rootdir/subdir/example.sas7bdat"; + run; + + %mp_deletefolder(&rootdir) + + @param path Unquoted path to the folder to delete. + +

SAS Macros

+ @li mf_getuniquename.sas + @li mf_isdir.sas + @li mp_dirlist.sas + +

Related Macros

+ @li mp_deletefolder.test.sas + +**/ + +%macro mp_deletefolder(folder); + /* proceed if valid directory */ + %if %mf_isdir(&folder)=1 %then %do; + + /* prep temp table */ + %local tempds; + %let tempds=%mf_getuniquename(); + + /* recursive directory listing */ + %mp_dirlist(path=&folder,outds=work.&tempds, maxdepth=MAX) + + /* sort descending level so can delete folder contents before folders */ + proc sort data=work.&tempds; + by descending level; + run; + + /* ensure top level folder is removed at the end */ + proc sql; + insert into work.&tempds set filepath="&folder"; + + /* delete everything */ + data _null_; + set work.&tempds end=last; + length fref $8; + rc=filename(fref,filepath); + rc=fdelete(fref); + if rc then do; + msg=sysmsg(); + put "&sysmacroname:" / rc= / msg= / filepath=; + end; + rc=filename(fref); + run; + + /* tidy up */ + proc sql; + drop table work.&tempds; + + %end; + %else %put &sysmacroname: &folder: is not a valid / accessible folder. ; +%mend mp_deletefolder;/** @file @brief Returns all files and subdirectories within a specified parent @details When used with getattrs=NO, is not OS specific (uses dopen / dread). @@ -3118,6 +3186,9 @@ run;

SAS Macros

@li mp_dropmembers.sas +

Related Macros

+ @li mp_dirlist.test.sas + @version 9.2 @author Allan Bowe **/ @@ -3138,7 +3209,7 @@ data;run; /* drop main (top) table if it exists */ %if &level=0 %then %do; - %mp_dropmembers(&outds, libref=WORK) + %mp_dropmembers(%scan(&outds,-1,.), libref=WORK) %end; data &out_ds(compress=no @@ -3253,12 +3324,12 @@ run; run; %end; -/* update main table */ -proc append base=&outds data=&out_ds; +data &out_ds; + set &out_ds(where=(filepath ne '')); run; -data &outds; - set &outds(where=(filepath ne '')); +/* update main table */ +proc append base=&outds data=&out_ds; run; /* recursive call */