1
0
mirror of https://github.com/sasjs/core.git synced 2025-12-24 11:41:20 +00:00

Compare commits

...

26 Commits

Author SHA1 Message Date
Allan Bowe
7b884d165f chore: automated commit 2021-06-21 17:21:45 +03:00
Allan Bowe
5a2968e798 fix: supporting LATIN1 as well as WLATIN1 in mm_webout 2021-06-17 16:31:29 +03:00
Allan Bowe
120ad9a7da fix: supporting bell cand escape characters when creating viya jobs / services with macro 2021-06-11 00:09:16 +03:00
Allan Bowe
67a81b2690 chore: updating the docs for mm_spkexport.sas 2021-06-08 20:09:23 +03:00
Allan Bowe
506cf1812f fix: deal with dashes in sysencoding 2021-06-08 16:59:43 +03:00
Allan Bowe
8cc0eb0dd7 Merge pull request #42 from sasjs/issue41
closes #42 Issue41
2021-06-03 22:44:16 +03:00
Allan Bowe
4c1f69da3a fix: using PROC JSON for JSON where SYSENCODING=wlatin1 2021-06-01 18:24:04 +03:00
Allan Bowe
f160ebe705 chore: updating all.sas from previous pushes 2021-06-01 18:01:01 +03:00
Allan Bowe
3f49925d01 Merge pull request #40 from sasjs/dependabot/npm_and_yarn/ws-7.4.6
chore(deps): bump ws from 7.4.5 to 7.4.6
2021-06-01 17:58:49 +03:00
Allan Bowe
53ed5dc916 fix: adding extra debugging to mf_getvarlist 2021-06-01 09:32:19 +03:00
Allan Bowe
808b24e31b chore: adding mend statement 2021-05-31 15:15:17 +03:00
dependabot[bot]
c51c9c2ca9 chore(deps): bump ws from 7.4.5 to 7.4.6
Bumps [ws](https://github.com/websockets/ws) from 7.4.5 to 7.4.6.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.4.5...7.4.6)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-31 02:08:52 +00:00
Allan Bowe
4d6edf5566 feat: additional options for mv_createfile.sas, also a log message to enable file to be easily opened 2021-05-30 13:22:50 +03:00
Allan Bowe
41a24677f5 chore: automated commit 2021-05-27 09:42:15 +03:00
Allan Bowe
e7d8d8ffb3 chore: updating docs 2021-05-27 09:40:38 +03:00
Allan Bowe
60d23dd618 Merge pull request #39 from sasjs/newviyafeatures
Newviyafeatures
2021-05-27 00:31:44 +03:00
Allan Bowe
d2764c3cd1 chore: updating all.sas 2021-05-26 23:37:38 +03:00
Allan Bowe
f9f4355143 feat: adding mv_createfile.sas and tests 2021-05-26 23:37:24 +03:00
Allan Bowe
18bc6c889d feat: adding mfv_existfolder.sas and tests 2021-05-26 23:37:06 +03:00
Allan Bowe
42a16ef496 feat: adding mfv_existfile.sas and tests 2021-05-26 23:36:43 +03:00
Allan Bowe
8178b801fb fix: using mfv_existfolder macro in mv_createfolder to save requests 2021-05-26 23:36:09 +03:00
Allan Bowe
ce331a23c8 fix: ensuring obs is updated when the table has zero columns 2021-05-26 23:35:25 +03:00
Allan Bowe
1cc9213467 feat: refreshing mf_abort (it's now an actual macro function) 2021-05-26 23:34:43 +03:00
Allan Bowe
aabbf4d0f9 Merge pull request #38 from sasjs/weboutfixes
fix: changing replace to YES in mm_createwebservice.sas, also setting…
2021-05-26 18:29:08 +03:00
Allan Bowe
2bea8be70d chore: logging in test 2021-05-26 18:19:04 +03:00
Allan Bowe
9b2368443e fix: changing replace to YES in mm_createwebservice.sas, also setting a default for code to ft15f001. More debugging added to mv_createfolder.sas 2021-05-26 10:36:45 +03:00
24 changed files with 1015 additions and 331 deletions

View File

@@ -6,7 +6,7 @@
"hasMacroParentheses": true,
"noNestedMacros": false,
"noSpacesInFileNames": true,
"maxLineLength": 135,
"maxLineLength": 230,
"lowerCaseFileNames": true,
"noTabIndentation": true,
"indentationMultiple": 2

606
all.sas
View File

@@ -18,19 +18,18 @@
options noquotelenmax;
/**
@file
@brief to be deprecated
@details We will deprecate this macro in 2022
@brief Abort, ungracefully
@details Will abort with a straightforward %abort if the condition is true.
As you can see, it's not a macro function.
Use mp_abort.sas instead.
<h4> Related Macros </h4>
@li mp_abort.sas
@version 9.2
@author Allan Bowe
@cond
**/
%macro mf_abort(mac=mf_abort.sas, type=, msg=, iftrue=%str(1=1)
%macro mf_abort(mac=mf_abort.sas, type=deprecated, msg=, iftrue=%str(1=1)
)/*/STORE SOURCE*/;
%if not(%eval(%unquote(&iftrue))) %then %return;
@@ -39,117 +38,9 @@ options noquotelenmax;
%if %length(&mac)>0 %then %put NOTE- called by &mac;
%put NOTE - &msg;
/* Stored Process Server web app context */
%if %symexist(_metaperson) or "&SYSPROCESSNAME"="Compute Server" %then %do;
options obs=max replace nosyntaxcheck mprint;
/* extract log err / warn, if exist */
%local logloc logline;
%global logmsg; /* capture global messages */
%if %symexist(SYSPRINTTOLOG) %then %let logloc=&SYSPRINTTOLOG;
%else %let logloc=%qsysfunc(getoption(LOG));
proc printto log=log;run;
%if %length(&logloc)>0 %then %do;
%let logline=0;
data _null_;
infile &logloc lrecl=5000;
input; putlog _infile_;
i=1;
retain logonce 0;
if (
_infile_=:"%str(WARN)ING" or _infile_=:"%str(ERR)OR"
) and logonce=0
then do;
call symputx('logline',_n_);
logonce+1;
end;
run;
/* capture log including lines BEFORE the err */
%if &logline>0 %then %do;
data _null_;
infile &logloc lrecl=5000;
input;
i=1;
stoploop=0;
if _n_ ge &logline-5 and stoploop=0 then do until (i>12);
call symputx('logmsg',catx('\n',symget('logmsg'),_infile_));
input;
i+1;
stoploop=1;
end;
if stoploop=1 then stop;
run;
%end;
%end;
%abort;
/* send response in SASjs JSON format */
data _null_;
file _webout mod lrecl=32000;
length msg $32767;
sasdatetime=datetime();
msg=cats(symget('msg'),'\n\nLog Extract:\n',symget('logmsg'));
/* escape the quotes */
msg=tranwrd(msg,'"','\"');
/* ditch the CRLFs as chrome complains */
msg=compress(msg,,'kw');
/* quote without quoting the quotes (which are escaped instead) */
msg=cats('"',msg,'"');
if symexist('_debug') then debug=symget('_debug');
if debug ge 131 then put '>>weboutBEGIN<<';
put '{"START_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '"';
put ',"sasjsAbort" : [{';
put ' "MSG":' msg ;
put ' ,"MAC": "' "&mac" '"}]';
put ",""SYSUSERID"" : ""&sysuserid"" ";
if symexist('_metauser') then do;
_METAUSER=quote(trim(symget('_METAUSER')));
put ",""_METAUSER"": " _METAUSER;
_METAPERSON=quote(trim(symget('_METAPERSON')));
put ',"_METAPERSON": ' _METAPERSON;
end;
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" ";
put ',"END_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '" ';
put "}" @;
%if &_debug ge 131 %then %do;
put '>>weboutEND<<';
%end;
run;
%let syscc=0;
%if %symexist(SYS_JES_JOB_URI) %then %do;
/* refer web service output to file service in one hit */
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI"
name="_webout.json";
%let rc=%sysfunc(fcopy(_web,_webout));
%end;
%else %do;
data _null_;
if symexist('sysprocessmode')
then if symget("sysprocessmode")="SAS Stored Process Server"
then rc=stpsrvset('program error', 0);
run;
%end;
/**
* endsas is reliable but kills some deployments.
* Abort variants are ungraceful (non zero return code)
* This approach lets SAS run silently until the end :-)
*/
%put _all_;
filename skip temp;
data _null_;
file skip;
put '%macro skip(); %macro skippy();';
run;
%inc skip;
%end;
%else %do;
%put _all_;
%abort cancel;
%end;
%mend;
%mend mf_abort;
/** @endcond *//**
@file mf_existds.sas
@@ -176,7 +67,8 @@ options noquotelenmax;
%if %sysfunc(exist(&libds)) ne 1 & %sysfunc(exist(&libds,VIEW)) ne 1 %then 0;
%else 1;
%mend;/**
%mend mf_existds;
/**
@file
@brief Checks whether a feature exists
@details Check to see if a feature is supported in your environment.
@@ -1084,7 +976,8 @@ options noquotelenmax;
%let rc=%sysfunc(close(&dsid));
%end;
%else %do;
%put unable to open &libds (rc=&dsid);
%put &sysmacroname: Unable to open &libds (rc=&dsid);
%put &sysmacroname: SYSMSG= %sysfunc(sysmsg());
%let rc=%sysfunc(close(&dsid));
%end;
&outvar
@@ -5149,7 +5042,8 @@ create table &outds (rename=(
%let fmtds=%scan(&syslast,2,.);
/* prepare formats and varnames */
data _null_;
set &fmtds end=last;
if _n_=1 then call symputx('nobs',nobs,'l');
set &fmtds end=last nobs=nobs;
name=upcase(name);
/* fix formats */
if type=2 or type=6 then do;
@@ -5175,7 +5069,6 @@ create table &outds (rename=(
call symputx(cats('len',_n_),newlen,'l');
call symputx(cats('fmt',_n_),fmt,'l');
call symputx(cats('type',_n_),type,'l');
if last then call symputx('nobs',_n_,'l');
run;
data &fmtds;
/* rename on entry */
@@ -8901,7 +8794,7 @@ Usage:
%webout(OBJ,example2) * Object format, easier to work with ;
%webout(CLOSE)
;;;;
%mm_createwebservice(path=/Public/app/common,name=appInit)
%mm_createwebservice(path=/Public/app/common,name=appInit,code=ft15f001)
<h4> SAS Macros </h4>
@li mm_createstp.sas
@@ -8916,12 +8809,15 @@ Usage:
@param desc= The description of the service (optional)
@param precode= Space separated list of filerefs, pointing to the code that
needs to be attached to the beginning of the service (optional)
@param code= Space seperated fileref(s) of the actual code to be added
@param server= The server which will run the STP. Server name or uri is fine.
@param mDebug= set to 1 to show debug messages in the log
@param replace= select YES to replace any existing service in that location
@param adapter= the macro uses the sasjs adapter by default. To use another
adapter, add a (different) fileref here.
@param code=(ft15f001) Space seperated fileref(s) of the actual code to be
added
@param server=(SASApp) The server which will run the STP. Server name or uri
is fine.
@param mDebug=(0) set to 1 to show debug messages in the log
@param replace=(YES) select NO to avoid replacing an existing service in that
location
@param adapter=(sasjs) the macro uses the sasjs adapter by default. To use
another adapter, add a (different) fileref here.
@version 9.2
@author Allan Bowe
@@ -8931,11 +8827,11 @@ Usage:
%macro mm_createwebservice(path=
,name=initService
,precode=
,code=
,code=ft15f001
,desc=This stp was created automagically by the mm_createwebservice macro
,mDebug=0
,server=SASApp
,replace=NO
,replace=YES
,adapter=sasjs
)/*/STORE SOURCE*/;
@@ -9010,7 +8906,8 @@ data _null_;
put ' %let fmtds=%scan(&syslast,2,.); ';
put ' /* prepare formats and varnames */ ';
put ' data _null_; ';
put ' set &fmtds end=last; ';
put ' if _n_=1 then call symputx(''nobs'',nobs,''l''); ';
put ' set &fmtds end=last nobs=nobs; ';
put ' name=upcase(name); ';
put ' /* fix formats */ ';
put ' if type=2 or type=6 then do; ';
@@ -9036,7 +8933,6 @@ data _null_;
put ' call symputx(cats(''len'',_n_),newlen,''l''); ';
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
put ' call symputx(cats(''type'',_n_),type,''l''); ';
put ' if last then call symputx(''nobs'',_n_,''l''); ';
put ' run; ';
put ' data &fmtds; ';
put ' /* rename on entry */ ';
@@ -9142,7 +9038,12 @@ data _null_;
put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y); ';
put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug ';
put ' sasjs_tables; ';
put '%local i tempds; ';
put '%local i tempds jsonengine; ';
put ' ';
put '/* see https://github.com/sasjs/core/issues/41 */ ';
put '%if "%upcase(&SYSENCODING)" ne "UTF-8" %then %let jsonengine=PROCJSON; ';
put '%else %let jsonengine=DATASTEP; ';
put ' ';
put ' ';
put '%if &action=FETCH %then %do; ';
put ' %if %str(&_debug) ge 131 %then %do; ';
@@ -9177,7 +9078,7 @@ data _null_;
put ' OPTIONS NOBOMFILE; ';
put ' ';
put ' /** ';
put ' * check engine type to avoid the below err message: ';
put ' * check xengine type to avoid the below err message: ';
put ' * > Function is only valid for filerefs using the CACHE access method. ';
put ' */ ';
put ' data _null_; ';
@@ -9199,7 +9100,7 @@ data _null_;
put ' ';
put '%else %if &action=ARR or &action=OBJ %then %do; ';
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref ';
put ' ,engine=DATASTEP,dbg=%str(&_debug) ';
put ' ,engine=&jsonengine,dbg=%str(&_debug) ';
put ' ) ';
put '%end; ';
put '%else %if &action=CLOSE %then %do; ';
@@ -9212,7 +9113,7 @@ data _null_;
put ' %local wtcnt;%let wtcnt=0; ';
put ' data _null_; ';
put ' set &tempds; ';
put ' if not (name =:"DATA"); ';
put ' if not (upcase(name) =:"DATA"); /* ignore temp datasets */ ';
put ' i+1; ';
put ' call symputx(''wt''!!left(i),name,''l''); ';
put ' call symputx(''wtcnt'',i,''l''); ';
@@ -9232,8 +9133,8 @@ data _null_;
put ' put " ""&wt"" : {"; ';
put ' put ''"nlobs":'' nlobs; ';
put ' put '',"nvars":'' nvars; ';
put ' %mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=DATASTEP) ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP) ';
put ' %mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=&jsonengine) ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=&jsonengine) ';
put ' data _null_; file &fref mod encoding=''utf-8''; ';
put ' put "}"; ';
put ' %end; ';
@@ -9347,7 +9248,7 @@ run;
%put &url?_PROGRAM=&path/&name;
%put ;%put ;%put ;%put ;%put ;%put ;
%mend;
%mend mm_createwebservice;
/**
@file mm_deletedocument.sas
@brief Deletes a Document using path as reference
@@ -11868,7 +11769,8 @@ filename __shake clear;
put '%let mmxpass="Mars321";';
run;
filename myref "%sysfunc(pathname(work))/mmxexport.sh";
filename myref "%sysfunc(pathname(work))/mmxexport.sh"
permission='A::u::rwx,A::g::r-x,A::o::---';
%mm_spkexport(metaloc=%str(/my/meta/loc)
,outref=myref
,secureref=tmp
@@ -11877,7 +11779,8 @@ filename __shake clear;
Alternatively, call without inputs to create a function style output
filename myref "/tmp/mmscript.sh";
filename myref "/tmp/mmscript.sh"
permission='A::u::rwx,A::g::r-x,A::o::---';
%mm_spkexport(metaloc=%str(/my/meta/loc)
outref=myref
,cmdoutloc=%str(/tmp)
@@ -11963,7 +11866,7 @@ run;
,msg=%str(syscc=&syscc)
)
%mend;/**
%mend mm_spkexport;/**
@file mm_tree.sas
@brief Returns all folders / subfolder content for a particular root
@details Shows all members and SubTrees for a particular root.
@@ -12628,7 +12531,12 @@ run;
%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y);
%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug
sasjs_tables;
%local i tempds;
%local i tempds jsonengine;
/* see https://github.com/sasjs/core/issues/41 */
%if "%upcase(&SYSENCODING)" ne "UTF-8" %then %let jsonengine=PROCJSON;
%else %let jsonengine=DATASTEP;
%if &action=FETCH %then %do;
%if %str(&_debug) ge 131 %then %do;
@@ -12663,7 +12571,7 @@ run;
OPTIONS NOBOMFILE;
/**
* check engine type to avoid the below err message:
* check xengine type to avoid the below err message:
* > Function is only valid for filerefs using the CACHE access method.
*/
data _null_;
@@ -12685,7 +12593,7 @@ run;
%else %if &action=ARR or &action=OBJ %then %do;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
,engine=DATASTEP,dbg=%str(&_debug)
,engine=&jsonengine,dbg=%str(&_debug)
)
%end;
%else %if &action=CLOSE %then %do;
@@ -12698,7 +12606,7 @@ run;
%local wtcnt;%let wtcnt=0;
data _null_;
set &tempds;
if not (name =:"DATA");
if not (upcase(name) =:"DATA"); /* ignore temp datasets */
i+1;
call symputx('wt'!!left(i),name,'l');
call symputx('wtcnt',i,'l');
@@ -12718,8 +12626,8 @@ run;
put " ""&wt"" : {";
put '"nlobs":' nlobs;
put ',"nvars":' nvars;
%mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=DATASTEP)
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP)
%mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=&jsonengine)
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=&jsonengine)
data _null_; file &fref mod encoding='utf-8';
put "}";
%end;
@@ -12795,6 +12703,98 @@ data _null_;
run;
%mend;/**
@file
@brief Get metadata permissions for a particular folder
@details Uses the metadata batch tools to fetch the permissions for a
particular folder. For security, the username / password are expected to have
been provided in a protected directory.
Usage:
%* import the macros (or make them available some other way);
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc;
%* create sample text file as input to the macro;
%* password must be in single quotes if it has special chars;
filename creds temp;
data _null_;
file creds;
put " -user 'sasdemo' -password 'Mars321' ";
run;
filename outref "%sysfunc(pathname(work))";
%mmx_getmetaperms(
metaloc=/some/meta/folder
,secureref=creds
,outds=work.perms
)
<h4> SAS Macros </h4>
@li mf_loc.sas
@li mf_getuniquefileref.sas
@li mp_abort.sas
@param metaloc= the metadata folder for which to export permissions
@param secureref= fileref containing the username / password (should point to
a file in a secure location)
@param outds= (work.mmx_getmetaperms) The output table containing the perms
@param effective= (YES) Displays effective access. If set to NO, only direct
access controls are displayed. Effective access is the net effect of all
applicable permission settings (both direct access controls and inherited
permissions).
@param onlyGroup= (0) Display access for only the specified user group.
@param onlyUser= (0) Display access for only the specified user.
@version 9.4
@author Allan Bowe
**/
%macro mmx_getmetaperms(metaloc=
,secureref=
,outds=work.mmx_getmetaperms
,effective=YES
,onlygroup=0
,onlyuser=0
);
%local host port path mmxuser mmxpass eff filt;
%let host=%sysfunc(getoption(metaserver));
%let port=%sysfunc(getoption(metaport));
%let path=%mf_loc(POF)/tools/sas-show-metadata-access;
%if &effective=YES %then %let eff=-effective;
%if "&onlygroup" ne "0" %then %let filt=-onlyGroup ""&onlygroup"";
%else %if "&onlyuser" ne "0" %then %let filt=-onlyUser ""&onlyuser"";
%local fref1;
%let fref1=%mf_getuniquefileref();
data _null_;
file &fref1 lrecl=32767;
infile &secureref;
input;
put 'data _null_;';
put "infile '&path -disableX11 -host &host -port &port " _infile_ @;
put " ""&metaloc"" &eff &filt 2>&1' pipe lrecl=10000;";
put 'input;putlog _infile_;run;';
run;
data _null_;
infile &fref1;
input;list;run;
%inc &fref1/nosource;
%mp_abort(iftrue= (&syscc ne 0)
,mac=&sysmacroname
,msg=%str(syscc=&syscc on exit)
)
%mend mmx_getmetaperms;/**
@file mmx_spkexport.sas
@brief Exports everything in a particular metadata folder
@details Will export everything in a metadata folder to a specified location.
@@ -12887,19 +12887,233 @@ run;
%inc &fref1;
%mend;/**
@file
@brief Checks whether a file exists in SAS Drive
@details Returns 1 if the file exists, and 0 if it doesn't. Works by
attempting to assign a fileref with the filesrvc engine. If not found, the
syscc is automatically set to a non zero value - so in this case it is reset.
To avoid hiding issues, there is therefore a test at the start to ensure the
syscc is zero.
Usage:
%put %mfv_existfile(/does/exist.txt);
%put %mfv_existfile(/does/not/exist.txt);
@param filepath The full path to the file on SAS drive (eg /Public/myfile.txt)
<h4> SAS Macros </h4>
@li mf_abort.sas
@li mf_getuniquefileref.sas
<h4> Related Macros </h4>
@li mfv_existfolder.sas
@version 3.5
@author [Allan Bowe](https://www.linkedin.com/in/allanbowe/)
**/
%macro mfv_existfile(filepath
)/*/STORE SOURCE*/;
%mf_abort(
iftrue=(&syscc ne 0),
msg=Cannot enter mfv_existfile.sas with syscc=&syscc
)
%local fref rc path name;
%let fref=%mf_getuniquefileref();
%let name=%scan(&filepath,-1,/);
%let path=%substr(&filepath,1,%length(&filepath)-%length(&name)-1);
%if %sysfunc(filename(fref,,filesrvc,folderPath="&path" filename="&name"))=0
%then %do;
%sysfunc(fexist(&fref))
%let rc=%sysfunc(filename(fref));
%end;
%else %do;
0
%let syscc=0;
%end;
%mend mfv_existfile;/**
@file
@brief Checks whether a folder exists in SAS Drive
@details Returns 1 if the folder exists, and 0 if it doesn't. Works by
attempting to assign a fileref with the filesrvc engine. If not found, the
syscc is automatically set to a non zero value - so in this case it is reset.
To avoid hiding issues, there is therefore a test at the start to ensure the
syscc is zero.
Usage:
%put %mfv_existfolder(/does/exist);
%put %mfv_existfolder(/does/not/exist);
@param path The path to the folder on SAS drive
<h4> SAS Macros </h4>
@li mf_abort.sas
@li mf_getuniquefileref.sas
<h4> Related Macros </h4>
@li mfv_existfile.sas
@version 3.5
@author [Allan Bowe](https://www.linkedin.com/in/allanbowe/)
**/
%macro mfv_existfolder(path
)/*/STORE SOURCE*/;
%mf_abort(
iftrue=(&syscc ne 0),
msg=Cannot enter mfv_existfolder.sas with syscc=&syscc
)
%local fref rc;
%let fref=%mf_getuniquefileref();
%if %sysfunc(filename(fref,,filesrvc,folderPath="&path"))=0 %then %do;
1
%let rc=%sysfunc(filename(fref));
%end;
%else %do;
0
%let syscc=0;
%end;
%mend mfv_existfolder;/**
@file
@brief Creates a file in SAS Drive
@details Creates a file in SAS Drive and adds the appropriate content type.
If the parent folder does not exist, it is created.
Usage:
filename myfile temp;
data _null_;
file myfile;
put 'something';
run;
%mv_createfile(path=/Public/temp,name=newfile.txt,inref=myfile)
@param [in] path= The parent folder in which to create the file
@param [in] name= The name of the file to be created
@param [in] inref= The fileref pointing to the file to be uploaded
@param [in] contentdisp= (inline) Content Disposition. Example values:
@li inline
@li attachment
@param [in] access_token_var= The global macro variable to contain the access
token, if using authorization_code grant type.
@param [in] grant_type= (sas_services) Valid values are:
@li password
@li authorization_code
@li sas_services
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
@version VIYA V.03.05
@author Allan Bowe, source: https://github.com/sasjs/core
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_isblank.sas
@li mp_abort.sas
@li mp_binarycopy.sas
@li mv_createfolder.sas
**/
%macro mv_createfile(path=
,name=
,inref=
,contentdisp=inline
,access_token_var=ACCESS_TOKEN
,grant_type=sas_services
,mdebug=0
);
%local dbg;
%if &mdebug=1 %then %do;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%else %let dbg=*;
%local oauth_bearer;
%if &grant_type=detect %then %do;
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
%else %let grant_type=sas_services;
%end;
%if &grant_type=sas_services %then %do;
%let oauth_bearer=oauth_bearer=sas_services;
%let &access_token_var=;
%end;
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
and &grant_type ne sas_services
)
,mac=&sysmacroname
,msg=%str(Invalid value for grant_type: &grant_type)
)
%mp_abort(iftrue=(%mf_isblank(&path)=1 or %length(&path)=1)
,mac=&sysmacroname
,msg=%str(path value must be provided)
)
%mp_abort(iftrue=(%mf_isblank(&name)=1 or %length(&name)=1)
,mac=&sysmacroname
,msg=%str(name value with length >1 must be provided)
)
/* create folder if it does not already exist */
%mv_createfolder(path=&path
,access_token_var=&access_token_var
,grant_type=&grant_type
,mdebug=&mdebug
)
/* create file with relevant options */
%local fref;
%let fref=%mf_getuniquefileref();
filename &fref filesrvc
folderPath="&path"
filename="&name"
cdisp="&contentdisp";
%mp_binarycopy(inref=&inref, outref=&fref)
filename &fref clear;
%local base_uri; /* location of rest apis */
%let base_uri=%mf_getplatform(VIYARESTAPI);
%put &sysmacroname: File &name successfully created in &path;
%put &sysmacroname:;%put;
%put &base_uri/SASJobExecution?_file=&path/&name;%put;
%put &sysmacroname:;
%mend mv_createfile;/**
@file mv_createfolder.sas
@brief Creates a viya folder if that folder does not already exist
@details Expects oauth token in a global macro variable (default
ACCESS_TOKEN).
@details Creates a viya folder by checking if each parent folder exists, and
recursively creating children if needed.
Usage:
%mv_createfolder(path=/Public)
@param path= The full path of the folder to be created
@param access_token_var= The global macro variable to contain the access token
@param grant_type= (authorization_code) Valid values are "password" or
"authorization_code" (unquoted).
@param [in] path= The full path of the folder to be created
@param [in] access_token_var= The global macro variable to contain the access
token, if using authorization_code grant type.
@param [in] grant_type= (sas_services) Valid values are:
@li password
@li authorization_code
@li sas_services
@param [in] mdebug=(0) set to 1 to enable DEBUG messages
@version VIYA V.03.04
@author Allan Bowe, source: https://github.com/sasjs/core
@@ -12910,21 +13124,36 @@ run;
@li mf_getuniquelibref.sas
@li mf_isblank.sas
@li mf_getplatform.sas
@li mfv_existfolder.sas
**/
%macro mv_createfolder(path=
,access_token_var=ACCESS_TOKEN
,grant_type=sas_services
,mdebug=0
);
%local dbg;
%if &mdebug=1 %then %do;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%else %let dbg=*;
%if %mfv_existfolder(&path)=1 %then %do;
%put &sysmacroname: &path already exists;
%return;
%end;
%local oauth_bearer;
%if &grant_type=detect %then %do;
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
%else %let grant_type=sas_services;
%end;
%if &grant_type=sas_services %then %do;
%let oauth_bearer=oauth_bearer=sas_services;
%let &access_token_var=;
%let oauth_bearer=oauth_bearer=sas_services;
%let &access_token_var=;
%end;
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
@@ -12979,6 +13208,15 @@ options noquotelenmax;
,mac=&sysmacroname
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
%if &mdebug=1 %then %do;
%put &sysmacroname following check to see if &newpath exists:;
%put _local_;
data _null_;
set &fname1;
input;
putlog _infile_;
run;
%end;
%if &SYS_PROCHTTP_STATUS_CODE=200 %then %do;
%*put &sysmacroname &newpath exists so grab the follow on link ;
data _null_;
@@ -13028,8 +13266,10 @@ options noquotelenmax;
%put &sysmacroname &newpath now created. Grabbing the follow on link ;
data _null_;
set &libref2..links;
if rel='createChild' then
if rel='createChild' then do;
call symputx('href',quote(cats("&base_uri",href)),'l');
&dbg put (_all_)(=);
end;
run;
libname &libref2 clear;
@@ -13277,6 +13517,30 @@ run;
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'\');rc =fwrite(fileid);
end;
else if rec='01'x then do; /* Unprintable */
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'u');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'1');rc =fwrite(fileid);
end;
else if rec='07'x then do; /* Bell Char */
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'u');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'7');rc =fwrite(fileid);
end;
else if rec='1B'x then do; /* escape char */
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'u');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'1');rc =fwrite(fileid);
rc =fput(fileid,'B');rc =fwrite(fileid);
end;
else do;
rc =fput(fileid,rec);
rc =fwrite(fileid);
@@ -13629,7 +13893,8 @@ data _null_;
put ' %let fmtds=%scan(&syslast,2,.); ';
put ' /* prepare formats and varnames */ ';
put ' data _null_; ';
put ' set &fmtds end=last; ';
put ' if _n_=1 then call symputx(''nobs'',nobs,''l''); ';
put ' set &fmtds end=last nobs=nobs; ';
put ' name=upcase(name); ';
put ' /* fix formats */ ';
put ' if type=2 or type=6 then do; ';
@@ -13655,7 +13920,6 @@ data _null_;
put ' call symputx(cats(''len'',_n_),newlen,''l''); ';
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
put ' call symputx(cats(''type'',_n_),type,''l''); ';
put ' if last then call symputx(''nobs'',_n_,''l''); ';
put ' run; ';
put ' data &fmtds; ';
put ' /* rename on entry */ ';
@@ -13896,8 +14160,9 @@ data _null_;
put ' ods output Members=&tempds; ';
put ' proc datasets library=WORK memtype=data; ';
put ' %local wtcnt;%let wtcnt=0; ';
put ' data _null_; set &tempds; ';
put ' if not (name =:"DATA"); ';
put ' data _null_; ';
put ' set &tempds; ';
put ' if not (upcase(name) =:"DATA"); /* ignore temp datasets */ ';
put ' i+1; ';
put ' call symputx(''wt''!!left(i),name); ';
put ' call symputx(''wtcnt'',i); ';
@@ -14021,6 +14286,22 @@ run;
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'1');rc =fwrite(fileid);
end;
else if rec='07'x then do; /* Bell Char */
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'u');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'7');rc =fwrite(fileid);
end;
else if rec='1B'x then do; /* escape char */
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'u');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'1');rc =fwrite(fileid);
rc =fput(fileid,'B');rc =fwrite(fileid);
end;
else do;
rc =fput(fileid,rec);
rc =fwrite(fileid);
@@ -17696,8 +17977,9 @@ filename &fref1 clear;
ods output Members=&tempds;
proc datasets library=WORK memtype=data;
%local wtcnt;%let wtcnt=0;
data _null_; set &tempds;
if not (name =:"DATA");
data _null_;
set &tempds;
if not (upcase(name) =:"DATA"); /* ignore temp datasets */
i+1;
call symputx('wt'!!left(i),name);
call symputx('wtcnt',i);

View File

@@ -1,18 +1,17 @@
/**
@file
@brief to be deprecated
@details We will deprecate this macro in 2022
@brief Abort, ungracefully
@details Will abort with a straightforward %abort if the condition is true.
As you can see, it's not a macro function.
Use mp_abort.sas instead.
<h4> Related Macros </h4>
@li mp_abort.sas
@version 9.2
@author Allan Bowe
@cond
**/
%macro mf_abort(mac=mf_abort.sas, type=, msg=, iftrue=%str(1=1)
%macro mf_abort(mac=mf_abort.sas, type=deprecated, msg=, iftrue=%str(1=1)
)/*/STORE SOURCE*/;
%if not(%eval(%unquote(&iftrue))) %then %return;
@@ -21,116 +20,8 @@
%if %length(&mac)>0 %then %put NOTE- called by &mac;
%put NOTE - &msg;
/* Stored Process Server web app context */
%if %symexist(_metaperson) or "&SYSPROCESSNAME"="Compute Server" %then %do;
options obs=max replace nosyntaxcheck mprint;
/* extract log err / warn, if exist */
%local logloc logline;
%global logmsg; /* capture global messages */
%if %symexist(SYSPRINTTOLOG) %then %let logloc=&SYSPRINTTOLOG;
%else %let logloc=%qsysfunc(getoption(LOG));
proc printto log=log;run;
%if %length(&logloc)>0 %then %do;
%let logline=0;
data _null_;
infile &logloc lrecl=5000;
input; putlog _infile_;
i=1;
retain logonce 0;
if (
_infile_=:"%str(WARN)ING" or _infile_=:"%str(ERR)OR"
) and logonce=0
then do;
call symputx('logline',_n_);
logonce+1;
end;
run;
/* capture log including lines BEFORE the err */
%if &logline>0 %then %do;
data _null_;
infile &logloc lrecl=5000;
input;
i=1;
stoploop=0;
if _n_ ge &logline-5 and stoploop=0 then do until (i>12);
call symputx('logmsg',catx('\n',symget('logmsg'),_infile_));
input;
i+1;
stoploop=1;
end;
if stoploop=1 then stop;
run;
%end;
%end;
%abort;
/* send response in SASjs JSON format */
data _null_;
file _webout mod lrecl=32000;
length msg $32767;
sasdatetime=datetime();
msg=cats(symget('msg'),'\n\nLog Extract:\n',symget('logmsg'));
/* escape the quotes */
msg=tranwrd(msg,'"','\"');
/* ditch the CRLFs as chrome complains */
msg=compress(msg,,'kw');
/* quote without quoting the quotes (which are escaped instead) */
msg=cats('"',msg,'"');
if symexist('_debug') then debug=symget('_debug');
if debug ge 131 then put '>>weboutBEGIN<<';
put '{"START_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '"';
put ',"sasjsAbort" : [{';
put ' "MSG":' msg ;
put ' ,"MAC": "' "&mac" '"}]';
put ",""SYSUSERID"" : ""&sysuserid"" ";
if symexist('_metauser') then do;
_METAUSER=quote(trim(symget('_METAUSER')));
put ",""_METAUSER"": " _METAUSER;
_METAPERSON=quote(trim(symget('_METAPERSON')));
put ',"_METAPERSON": ' _METAPERSON;
end;
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
put ',"_PROGRAM" : ' _PROGRAM ;
put ",""SYSCC"" : ""&syscc"" ";
put ",""SYSERRORTEXT"" : ""&syserrortext"" ";
put ",""SYSJOBID"" : ""&sysjobid"" ";
put ",""SYSWARNINGTEXT"" : ""&syswarningtext"" ";
put ',"END_DTTM" : "' "%sysfunc(datetime(),datetime20.3)" '" ';
put "}" @;
%if &_debug ge 131 %then %do;
put '>>weboutEND<<';
%end;
run;
%let syscc=0;
%if %symexist(SYS_JES_JOB_URI) %then %do;
/* refer web service output to file service in one hit */
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI"
name="_webout.json";
%let rc=%sysfunc(fcopy(_web,_webout));
%end;
%else %do;
data _null_;
if symexist('sysprocessmode')
then if symget("sysprocessmode")="SAS Stored Process Server"
then rc=stpsrvset('program error', 0);
run;
%end;
/**
* endsas is reliable but kills some deployments.
* Abort variants are ungraceful (non zero return code)
* This approach lets SAS run silently until the end :-)
*/
%put _all_;
filename skip temp;
data _null_;
file skip;
put '%macro skip(); %macro skippy();';
run;
%inc skip;
%end;
%else %do;
%put _all_;
%abort cancel;
%end;
%mend;
%mend mf_abort;
/** @endcond */

View File

@@ -23,4 +23,4 @@
%if %sysfunc(exist(&libds)) ne 1 & %sysfunc(exist(&libds,VIEW)) ne 1 %then 0;
%else 1;
%mend;
%mend mf_existds;

View File

@@ -66,7 +66,8 @@
%let rc=%sysfunc(close(&dsid));
%end;
%else %do;
%put unable to open &libds (rc=&dsid);
%put &sysmacroname: Unable to open &libds (rc=&dsid);
%put &sysmacroname: SYSMSG= %sysfunc(sysmsg());
%let rc=%sysfunc(close(&dsid));
%end;
&outvar

View File

@@ -102,7 +102,8 @@
%let fmtds=%scan(&syslast,2,.);
/* prepare formats and varnames */
data _null_;
set &fmtds end=last;
if _n_=1 then call symputx('nobs',nobs,'l');
set &fmtds end=last nobs=nobs;
name=upcase(name);
/* fix formats */
if type=2 or type=6 then do;
@@ -128,7 +129,6 @@
call symputx(cats('len',_n_),newlen,'l');
call symputx(cats('fmt',_n_),fmt,'l');
call symputx(cats('type',_n_),type,'l');
if last then call symputx('nobs',_n_,'l');
run;
data &fmtds;
/* rename on entry */

View File

@@ -42,6 +42,13 @@
*/
/*! \dir Tests
* \brief SASjs Tests
* \details These folders contain the macro tests. They are first compiled
and deployed (sasjs cbd) then executed (sasjs test).
*/
/*! \dir viya
* \brief Viya macros
* \details These macros have the following attributes:

View File

@@ -22,7 +22,7 @@ Usage:
%webout(OBJ,example2) * Object format, easier to work with ;
%webout(CLOSE)
;;;;
%mm_createwebservice(path=/Public/app/common,name=appInit)
%mm_createwebservice(path=/Public/app/common,name=appInit,code=ft15f001)
<h4> SAS Macros </h4>
@li mm_createstp.sas
@@ -37,12 +37,15 @@ Usage:
@param desc= The description of the service (optional)
@param precode= Space separated list of filerefs, pointing to the code that
needs to be attached to the beginning of the service (optional)
@param code= Space seperated fileref(s) of the actual code to be added
@param server= The server which will run the STP. Server name or uri is fine.
@param mDebug= set to 1 to show debug messages in the log
@param replace= select YES to replace any existing service in that location
@param adapter= the macro uses the sasjs adapter by default. To use another
adapter, add a (different) fileref here.
@param code=(ft15f001) Space seperated fileref(s) of the actual code to be
added
@param server=(SASApp) The server which will run the STP. Server name or uri
is fine.
@param mDebug=(0) set to 1 to show debug messages in the log
@param replace=(YES) select NO to avoid replacing an existing service in that
location
@param adapter=(sasjs) the macro uses the sasjs adapter by default. To use
another adapter, add a (different) fileref here.
@version 9.2
@author Allan Bowe
@@ -52,11 +55,11 @@ Usage:
%macro mm_createwebservice(path=
,name=initService
,precode=
,code=
,code=ft15f001
,desc=This stp was created automagically by the mm_createwebservice macro
,mDebug=0
,server=SASApp
,replace=NO
,replace=YES
,adapter=sasjs
)/*/STORE SOURCE*/;
@@ -131,7 +134,8 @@ data _null_;
put ' %let fmtds=%scan(&syslast,2,.); ';
put ' /* prepare formats and varnames */ ';
put ' data _null_; ';
put ' set &fmtds end=last; ';
put ' if _n_=1 then call symputx(''nobs'',nobs,''l''); ';
put ' set &fmtds end=last nobs=nobs; ';
put ' name=upcase(name); ';
put ' /* fix formats */ ';
put ' if type=2 or type=6 then do; ';
@@ -157,7 +161,6 @@ data _null_;
put ' call symputx(cats(''len'',_n_),newlen,''l''); ';
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
put ' call symputx(cats(''type'',_n_),type,''l''); ';
put ' if last then call symputx(''nobs'',_n_,''l''); ';
put ' run; ';
put ' data &fmtds; ';
put ' /* rename on entry */ ';
@@ -263,7 +266,12 @@ data _null_;
put '%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y); ';
put '%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug ';
put ' sasjs_tables; ';
put '%local i tempds; ';
put '%local i tempds jsonengine; ';
put ' ';
put '/* see https://github.com/sasjs/core/issues/41 */ ';
put '%if "%upcase(&SYSENCODING)" ne "UTF-8" %then %let jsonengine=PROCJSON; ';
put '%else %let jsonengine=DATASTEP; ';
put ' ';
put ' ';
put '%if &action=FETCH %then %do; ';
put ' %if %str(&_debug) ge 131 %then %do; ';
@@ -298,7 +306,7 @@ data _null_;
put ' OPTIONS NOBOMFILE; ';
put ' ';
put ' /** ';
put ' * check engine type to avoid the below err message: ';
put ' * check xengine type to avoid the below err message: ';
put ' * > Function is only valid for filerefs using the CACHE access method. ';
put ' */ ';
put ' data _null_; ';
@@ -320,7 +328,7 @@ data _null_;
put ' ';
put '%else %if &action=ARR or &action=OBJ %then %do; ';
put ' %mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref ';
put ' ,engine=DATASTEP,dbg=%str(&_debug) ';
put ' ,engine=&jsonengine,dbg=%str(&_debug) ';
put ' ) ';
put '%end; ';
put '%else %if &action=CLOSE %then %do; ';
@@ -333,7 +341,7 @@ data _null_;
put ' %local wtcnt;%let wtcnt=0; ';
put ' data _null_; ';
put ' set &tempds; ';
put ' if not (name =:"DATA"); ';
put ' if not (upcase(name) =:"DATA"); /* ignore temp datasets */ ';
put ' i+1; ';
put ' call symputx(''wt''!!left(i),name,''l''); ';
put ' call symputx(''wtcnt'',i,''l''); ';
@@ -353,8 +361,8 @@ data _null_;
put ' put " ""&wt"" : {"; ';
put ' put ''"nlobs":'' nlobs; ';
put ' put '',"nvars":'' nvars; ';
put ' %mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=DATASTEP) ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP) ';
put ' %mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=&jsonengine) ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=&jsonengine) ';
put ' data _null_; file &fref mod encoding=''utf-8''; ';
put ' put "}"; ';
put ' %end; ';
@@ -468,4 +476,4 @@ run;
%put &url?_PROGRAM=&path/&name;
%put ;%put ;%put ;%put ;%put ;%put ;
%mend;
%mend mm_createwebservice;

View File

@@ -24,7 +24,8 @@
put '%let mmxpass="Mars321";';
run;
filename myref "%sysfunc(pathname(work))/mmxexport.sh";
filename myref "%sysfunc(pathname(work))/mmxexport.sh"
permission='A::u::rwx,A::g::r-x,A::o::---';
%mm_spkexport(metaloc=%str(/my/meta/loc)
,outref=myref
,secureref=tmp
@@ -33,7 +34,8 @@
Alternatively, call without inputs to create a function style output
filename myref "/tmp/mmscript.sh";
filename myref "/tmp/mmscript.sh"
permission='A::u::rwx,A::g::r-x,A::o::---';
%mm_spkexport(metaloc=%str(/my/meta/loc)
outref=myref
,cmdoutloc=%str(/tmp)
@@ -119,4 +121,4 @@ run;
,msg=%str(syscc=&syscc)
)
%mend;
%mend mm_spkexport;

View File

@@ -36,7 +36,12 @@
%macro mm_webout(action,ds,dslabel=,fref=_webout,fmt=Y);
%global _webin_file_count _webin_fileref1 _webin_name1 _program _debug
sasjs_tables;
%local i tempds;
%local i tempds jsonengine;
/* see https://github.com/sasjs/core/issues/41 */
%if "%upcase(&SYSENCODING)" ne "UTF-8" %then %let jsonengine=PROCJSON;
%else %let jsonengine=DATASTEP;
%if &action=FETCH %then %do;
%if %str(&_debug) ge 131 %then %do;
@@ -71,7 +76,7 @@
OPTIONS NOBOMFILE;
/**
* check engine type to avoid the below err message:
* check xengine type to avoid the below err message:
* > Function is only valid for filerefs using the CACHE access method.
*/
data _null_;
@@ -93,7 +98,7 @@
%else %if &action=ARR or &action=OBJ %then %do;
%mp_jsonout(&action,&ds,dslabel=&dslabel,fmt=&fmt,jref=&fref
,engine=DATASTEP,dbg=%str(&_debug)
,engine=&jsonengine,dbg=%str(&_debug)
)
%end;
%else %if &action=CLOSE %then %do;
@@ -106,7 +111,7 @@
%local wtcnt;%let wtcnt=0;
data _null_;
set &tempds;
if not (name =:"DATA");
if not (upcase(name) =:"DATA"); /* ignore temp datasets */
i+1;
call symputx('wt'!!left(i),name,'l');
call symputx('wtcnt',i,'l');
@@ -126,8 +131,8 @@
put " ""&wt"" : {";
put '"nlobs":' nlobs;
put ',"nvars":' nvars;
%mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=DATASTEP)
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=DATASTEP)
%mp_jsonout(OBJ,&tempds,jref=&fref,dslabel=colattrs,engine=&jsonengine)
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,engine=&jsonengine)
data _null_; file &fref mod encoding='utf-8';
put "}";
%end;

View File

@@ -0,0 +1,93 @@
/**
@file
@brief Get metadata permissions for a particular folder
@details Uses the metadata batch tools to fetch the permissions for a
particular folder. For security, the username / password are expected to have
been provided in a protected directory.
Usage:
%* import the macros (or make them available some other way);
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc;
%* create sample text file as input to the macro;
%* password must be in single quotes if it has special chars;
filename creds temp;
data _null_;
file creds;
put " -user 'sasdemo' -password 'Mars321' ";
run;
filename outref "%sysfunc(pathname(work))";
%mmx_getmetaperms(
metaloc=/some/meta/folder
,secureref=creds
,outds=work.perms
)
<h4> SAS Macros </h4>
@li mf_loc.sas
@li mf_getuniquefileref.sas
@li mp_abort.sas
@param metaloc= the metadata folder for which to export permissions
@param secureref= fileref containing the username / password (should point to
a file in a secure location)
@param outds= (work.mmx_getmetaperms) The output table containing the perms
@param effective= (YES) Displays effective access. If set to NO, only direct
access controls are displayed. Effective access is the net effect of all
applicable permission settings (both direct access controls and inherited
permissions).
@param onlyGroup= (0) Display access for only the specified user group.
@param onlyUser= (0) Display access for only the specified user.
@version 9.4
@author Allan Bowe
**/
%macro mmx_getmetaperms(metaloc=
,secureref=
,outds=work.mmx_getmetaperms
,effective=YES
,onlygroup=0
,onlyuser=0
);
%local host port path mmxuser mmxpass eff filt;
%let host=%sysfunc(getoption(metaserver));
%let port=%sysfunc(getoption(metaport));
%let path=%mf_loc(POF)/tools/sas-show-metadata-access;
%if &effective=YES %then %let eff=-effective;
%if "&onlygroup" ne "0" %then %let filt=-onlyGroup ""&onlygroup"";
%else %if "&onlyuser" ne "0" %then %let filt=-onlyUser ""&onlyuser"";
%local fref1;
%let fref1=%mf_getuniquefileref();
data _null_;
file &fref1 lrecl=32767;
infile &secureref;
input;
put 'data _null_;';
put "infile '&path -disableX11 -host &host -port &port " _infile_ @;
put " ""&metaloc"" &eff &filt 2>&1' pipe lrecl=10000;";
put 'input;putlog _infile_;run;';
run;
data _null_;
infile &fref1;
input;list;run;
%inc &fref1/nosource;
%mp_abort(iftrue= (&syscc ne 0)
,mac=&sysmacroname
,msg=%str(syscc=&syscc on exit)
)
%mend mmx_getmetaperms;

6
package-lock.json generated
View File

@@ -1579,9 +1579,9 @@
"dev": true
},
"ws": {
"version": "7.4.5",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz",
"integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==",
"version": "7.4.6",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
"dev": true
},
"xml-name-validator": {

View File

@@ -30,13 +30,16 @@
"name": "viya",
"serverUrl": "https://sas.analytium.co.uk",
"serverType": "SASVIYA",
"allowInsecureRequests": false,
"appLoc": "/Public/temp/macrocore",
"deployConfig": {
"deployServicePack": true
},
"macroFolders": [
"tests/viya"
],
"programFolders": [],
"deployConfig": {
"deployServicePack": true,
"deployScripts": []
},
"contextName": "SAS Job Execution compute context"
},
{

View File

@@ -0,0 +1,34 @@
/**
@file
@brief Testing mfv_existfile macro function
<h4> SAS Macros </h4>
@li mf_uid.sas
@li mfv_existfile.sas
@li mp_assert.sas
@li mv_createfile.sas
**/
options mprint sgen;
%let file=%mf_uid();
/* create a folder */
filename somefile temp;
data _null_;
file somefile;
put 'hello testings';
run;
%mv_createfile(path=&mcTestAppLoc/temp, name=&file..txt,inref=somefile)
%mp_assert(
iftrue=(%mfv_existfile(&mcTestAppLoc/temp/&file..txt)=1),
desc=Check if created file exists
)
%mp_assert(
iftrue=(%mfv_existfile(&mcTestAppLoc/temp/%mf_uid().txt)=0),
desc=Check if non created file does not exist
)

View File

@@ -0,0 +1,29 @@
/**
@file
@brief Testing mfv_existfolder macro function
<h4> SAS Macros </h4>
@li mf_uid.sas
@li mfv_existfolder.sas
@li mp_assert.sas
@li mv_createfolder.sas
**/
options mprint sgen;
%let folder=%mf_uid();
/* create a folder */
%mv_createfolder(path=&mcTestAppLoc/temp/&folder)
%mp_assert(
iftrue=(%mfv_existfolder(&mcTestAppLoc/temp/&folder)=1),
desc=Check if created folder exists
)
%mp_assert(
iftrue=(%mfv_existfolder(&mcTestAppLoc/temp/&folder/%mf_uid()/noway)=0),
desc=Check if non created folder does not exist
)

View File

@@ -0,0 +1,42 @@
/**
@file
@brief Testing mv_createfile macro
<h4> SAS Macros </h4>
@li mf_uid.sas
@li mfv_existfile.sas
@li mp_assert.sas
@li mv_createfile.sas
**/
options mprint;
%let file=%mf_uid();
%put TEST 1 - basic file upload ;
filename somefile temp;
data _null_;
file somefile;
put 'hello testings';
run;
%mv_createfile(path=&mcTestAppLoc/temp, name=&file..txt,inref=somefile)
%mp_assert(
iftrue=(%mfv_existfile(&mcTestAppLoc/temp/&file..txt)=1),
desc=Check if created file exists
)
%put TEST 2 - dataset upload ;
data temp;
x=1;
run;
filename ds "%sysfunc(pathname(work))/temp.sas7bdat";
%mv_createfile(path=&mcTestAppLoc/temp, name=&file..sas7bdat,inref=ds)
%mp_assert(
iftrue=(%mfv_existfile(&mcTestAppLoc/temp/&file..sas7bdat)=1),
desc=Check if created dataset exists
)

View File

@@ -10,6 +10,8 @@
**/
options mprint notes;
/**
* Test Case 1
*/

51
viya/mfv_existfile.sas Normal file
View File

@@ -0,0 +1,51 @@
/**
@file
@brief Checks whether a file exists in SAS Drive
@details Returns 1 if the file exists, and 0 if it doesn't. Works by
attempting to assign a fileref with the filesrvc engine. If not found, the
syscc is automatically set to a non zero value - so in this case it is reset.
To avoid hiding issues, there is therefore a test at the start to ensure the
syscc is zero.
Usage:
%put %mfv_existfile(/does/exist.txt);
%put %mfv_existfile(/does/not/exist.txt);
@param filepath The full path to the file on SAS drive (eg /Public/myfile.txt)
<h4> SAS Macros </h4>
@li mf_abort.sas
@li mf_getuniquefileref.sas
<h4> Related Macros </h4>
@li mfv_existfolder.sas
@version 3.5
@author [Allan Bowe](https://www.linkedin.com/in/allanbowe/)
**/
%macro mfv_existfile(filepath
)/*/STORE SOURCE*/;
%mf_abort(
iftrue=(&syscc ne 0),
msg=Cannot enter mfv_existfile.sas with syscc=&syscc
)
%local fref rc path name;
%let fref=%mf_getuniquefileref();
%let name=%scan(&filepath,-1,/);
%let path=%substr(&filepath,1,%length(&filepath)-%length(&name)-1);
%if %sysfunc(filename(fref,,filesrvc,folderPath="&path" filename="&name"))=0
%then %do;
%sysfunc(fexist(&fref))
%let rc=%sysfunc(filename(fref));
%end;
%else %do;
0
%let syscc=0;
%end;
%mend mfv_existfile;

48
viya/mfv_existfolder.sas Normal file
View File

@@ -0,0 +1,48 @@
/**
@file
@brief Checks whether a folder exists in SAS Drive
@details Returns 1 if the folder exists, and 0 if it doesn't. Works by
attempting to assign a fileref with the filesrvc engine. If not found, the
syscc is automatically set to a non zero value - so in this case it is reset.
To avoid hiding issues, there is therefore a test at the start to ensure the
syscc is zero.
Usage:
%put %mfv_existfolder(/does/exist);
%put %mfv_existfolder(/does/not/exist);
@param path The path to the folder on SAS drive
<h4> SAS Macros </h4>
@li mf_abort.sas
@li mf_getuniquefileref.sas
<h4> Related Macros </h4>
@li mfv_existfile.sas
@version 3.5
@author [Allan Bowe](https://www.linkedin.com/in/allanbowe/)
**/
%macro mfv_existfolder(path
)/*/STORE SOURCE*/;
%mf_abort(
iftrue=(&syscc ne 0),
msg=Cannot enter mfv_existfolder.sas with syscc=&syscc
)
%local fref rc;
%let fref=%mf_getuniquefileref();
%if %sysfunc(filename(fref,,filesrvc,folderPath="&path"))=0 %then %do;
1
%let rc=%sysfunc(filename(fref));
%end;
%else %do;
0
%let syscc=0;
%end;
%mend mfv_existfolder;

113
viya/mv_createfile.sas Normal file
View File

@@ -0,0 +1,113 @@
/**
@file
@brief Creates a file in SAS Drive
@details Creates a file in SAS Drive and adds the appropriate content type.
If the parent folder does not exist, it is created.
Usage:
filename myfile temp;
data _null_;
file myfile;
put 'something';
run;
%mv_createfile(path=/Public/temp,name=newfile.txt,inref=myfile)
@param [in] path= The parent folder in which to create the file
@param [in] name= The name of the file to be created
@param [in] inref= The fileref pointing to the file to be uploaded
@param [in] contentdisp= (inline) Content Disposition. Example values:
@li inline
@li attachment
@param [in] access_token_var= The global macro variable to contain the access
token, if using authorization_code grant type.
@param [in] grant_type= (sas_services) Valid values are:
@li password
@li authorization_code
@li sas_services
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
@version VIYA V.03.05
@author Allan Bowe, source: https://github.com/sasjs/core
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_isblank.sas
@li mp_abort.sas
@li mp_binarycopy.sas
@li mv_createfolder.sas
**/
%macro mv_createfile(path=
,name=
,inref=
,contentdisp=inline
,access_token_var=ACCESS_TOKEN
,grant_type=sas_services
,mdebug=0
);
%local dbg;
%if &mdebug=1 %then %do;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%else %let dbg=*;
%local oauth_bearer;
%if &grant_type=detect %then %do;
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
%else %let grant_type=sas_services;
%end;
%if &grant_type=sas_services %then %do;
%let oauth_bearer=oauth_bearer=sas_services;
%let &access_token_var=;
%end;
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
and &grant_type ne sas_services
)
,mac=&sysmacroname
,msg=%str(Invalid value for grant_type: &grant_type)
)
%mp_abort(iftrue=(%mf_isblank(&path)=1 or %length(&path)=1)
,mac=&sysmacroname
,msg=%str(path value must be provided)
)
%mp_abort(iftrue=(%mf_isblank(&name)=1 or %length(&name)=1)
,mac=&sysmacroname
,msg=%str(name value with length >1 must be provided)
)
/* create folder if it does not already exist */
%mv_createfolder(path=&path
,access_token_var=&access_token_var
,grant_type=&grant_type
,mdebug=&mdebug
)
/* create file with relevant options */
%local fref;
%let fref=%mf_getuniquefileref();
filename &fref filesrvc
folderPath="&path"
filename="&name"
cdisp="&contentdisp";
%mp_binarycopy(inref=&inref, outref=&fref)
filename &fref clear;
%local base_uri; /* location of rest apis */
%let base_uri=%mf_getplatform(VIYARESTAPI);
%put &sysmacroname: File &name successfully created in &path;
%put &sysmacroname:;%put;
%put &base_uri/SASJobExecution?_file=&path/&name;%put;
%put &sysmacroname:;
%mend mv_createfile;

View File

@@ -1,17 +1,22 @@
/**
@file mv_createfolder.sas
@brief Creates a viya folder if that folder does not already exist
@details Expects oauth token in a global macro variable (default
ACCESS_TOKEN).
@details Creates a viya folder by checking if each parent folder exists, and
recursively creating children if needed.
Usage:
%mv_createfolder(path=/Public)
@param path= The full path of the folder to be created
@param access_token_var= The global macro variable to contain the access token
@param grant_type= (authorization_code) Valid values are "password" or
"authorization_code" (unquoted).
@param [in] path= The full path of the folder to be created
@param [in] access_token_var= The global macro variable to contain the access
token, if using authorization_code grant type.
@param [in] grant_type= (sas_services) Valid values are:
@li password
@li authorization_code
@li sas_services
@param [in] mdebug=(0) set to 1 to enable DEBUG messages
@version VIYA V.03.04
@author Allan Bowe, source: https://github.com/sasjs/core
@@ -22,21 +27,36 @@
@li mf_getuniquelibref.sas
@li mf_isblank.sas
@li mf_getplatform.sas
@li mfv_existfolder.sas
**/
%macro mv_createfolder(path=
,access_token_var=ACCESS_TOKEN
,grant_type=sas_services
,mdebug=0
);
%local dbg;
%if &mdebug=1 %then %do;
%put &sysmacroname entry vars:;
%put _local_;
%end;
%else %let dbg=*;
%if %mfv_existfolder(&path)=1 %then %do;
%put &sysmacroname: &path already exists;
%return;
%end;
%local oauth_bearer;
%if &grant_type=detect %then %do;
%if %symexist(&access_token_var) %then %let grant_type=authorization_code;
%else %let grant_type=sas_services;
%end;
%if &grant_type=sas_services %then %do;
%let oauth_bearer=oauth_bearer=sas_services;
%let &access_token_var=;
%let oauth_bearer=oauth_bearer=sas_services;
%let &access_token_var=;
%end;
%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
@@ -91,6 +111,15 @@ options noquotelenmax;
,mac=&sysmacroname
,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
)
%if &mdebug=1 %then %do;
%put &sysmacroname following check to see if &newpath exists:;
%put _local_;
data _null_;
set &fname1;
input;
putlog _infile_;
run;
%end;
%if &SYS_PROCHTTP_STATUS_CODE=200 %then %do;
%*put &sysmacroname &newpath exists so grab the follow on link ;
data _null_;
@@ -140,8 +169,10 @@ options noquotelenmax;
%put &sysmacroname &newpath now created. Grabbing the follow on link ;
data _null_;
set &libref2..links;
if rel='createChild' then
if rel='createChild' then do;
call symputx('href',quote(cats("&base_uri",href)),'l');
&dbg put (_all_)(=);
end;
run;
libname &libref2 clear;

View File

@@ -237,6 +237,30 @@ run;
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'\');rc =fwrite(fileid);
end;
else if rec='01'x then do; /* Unprintable */
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'u');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'1');rc =fwrite(fileid);
end;
else if rec='07'x then do; /* Bell Char */
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'u');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'7');rc =fwrite(fileid);
end;
else if rec='1B'x then do; /* escape char */
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'u');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'1');rc =fwrite(fileid);
rc =fput(fileid,'B');rc =fwrite(fileid);
end;
else do;
rc =fput(fileid,rec);
rc =fwrite(fileid);

View File

@@ -282,7 +282,8 @@ data _null_;
put ' %let fmtds=%scan(&syslast,2,.); ';
put ' /* prepare formats and varnames */ ';
put ' data _null_; ';
put ' set &fmtds end=last; ';
put ' if _n_=1 then call symputx(''nobs'',nobs,''l''); ';
put ' set &fmtds end=last nobs=nobs; ';
put ' name=upcase(name); ';
put ' /* fix formats */ ';
put ' if type=2 or type=6 then do; ';
@@ -308,7 +309,6 @@ data _null_;
put ' call symputx(cats(''len'',_n_),newlen,''l''); ';
put ' call symputx(cats(''fmt'',_n_),fmt,''l''); ';
put ' call symputx(cats(''type'',_n_),type,''l''); ';
put ' if last then call symputx(''nobs'',_n_,''l''); ';
put ' run; ';
put ' data &fmtds; ';
put ' /* rename on entry */ ';
@@ -549,8 +549,9 @@ data _null_;
put ' ods output Members=&tempds; ';
put ' proc datasets library=WORK memtype=data; ';
put ' %local wtcnt;%let wtcnt=0; ';
put ' data _null_; set &tempds; ';
put ' if not (name =:"DATA"); ';
put ' data _null_; ';
put ' set &tempds; ';
put ' if not (upcase(name) =:"DATA"); /* ignore temp datasets */ ';
put ' i+1; ';
put ' call symputx(''wt''!!left(i),name); ';
put ' call symputx(''wtcnt'',i); ';
@@ -674,6 +675,22 @@ run;
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'1');rc =fwrite(fileid);
end;
else if rec='07'x then do; /* Bell Char */
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'u');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'7');rc =fwrite(fileid);
end;
else if rec='1B'x then do; /* escape char */
rc =fput(fileid,'\');rc =fwrite(fileid);
rc =fput(fileid,'u');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'0');rc =fwrite(fileid);
rc =fput(fileid,'1');rc =fwrite(fileid);
rc =fput(fileid,'B');rc =fwrite(fileid);
end;
else do;
rc =fput(fileid,rec);
rc =fwrite(fileid);

View File

@@ -174,8 +174,9 @@
ods output Members=&tempds;
proc datasets library=WORK memtype=data;
%local wtcnt;%let wtcnt=0;
data _null_; set &tempds;
if not (name =:"DATA");
data _null_;
set &tempds;
if not (upcase(name) =:"DATA"); /* ignore temp datasets */
i+1;
call symputx('wt'!!left(i),name);
call symputx('wtcnt',i);