1
0
mirror of https://github.com/sasjs/core.git synced 2026-01-04 08:00:05 +00:00

Compare commits

..

25 Commits

Author SHA1 Message Date
Allan Bowe
7726b0e0b0 Merge pull request #206 from sasjs/ms_getfile
fix: ensuring ms_getfile works on specific installs
2022-03-29 20:41:20 +03:00
munja
0a536245f3 fix: missing dependency in mp_hashdataset.test.sas 2022-03-29 18:40:58 +01:00
munja
edfa9ecc07 fix: ensuring ms_getfile works on specific installs 2022-03-29 18:08:24 +01:00
munja
f4982c85ca fix: adding nonote2err option on mp_hashdataset 2022-03-29 15:00:33 +01:00
Allan Bowe
3ce771d587 Merge pull request #205 from sasjs/issue204
fix: updating mp_hashdataset to cope with STRICT mode.  Adding test a…
2022-03-29 15:47:17 +03:00
munja
72d6b446c3 fix: updating mp_hashdataset to cope with STRICT mode. Adding test and improving sasjs/server compatibility. 2022-03-29 13:22:24 +01:00
Allan Bowe
40d694eec8 Merge pull request #203 from sasjs/invisibles
fix: support SOH, STX and DC1 control characters in mp_jsonout
2022-03-29 12:02:09 +03:00
munja
6af1423666 fix: more invisibles 2022-03-28 16:26:58 +01:00
munja
23a01347f1 fix: support SOH, STX and DC1 control characters in mp_jsonout 2022-03-28 15:54:28 +01:00
Allan Bowe
7c86d6163a Merge pull request #201 from sasjs/mm_assignlib_fix
fix: enabling more descriptive mm_assignlib abort messages when library cannot be assigned
2022-03-21 18:10:56 +02:00
munja
d7233208f1 fix: enabling more descriptive mm_assignlib abort messages when library cannot be assigned 2022-03-21 16:07:27 +00:00
Allan Bowe
7f587ba720 Merge pull request #200 from sasjs/server
fix: headers in ms_createfile.sas
2022-03-19 02:23:57 +02:00
munja
21ecc1b675 fix: headers in ms_createfile.sas 2022-03-19 00:20:05 +00:00
Allan Bowe
6b13dc2b87 Merge pull request #199 from sasjs/server
fix: missing dependency in mv_deleteviyafolder
2022-03-16 18:07:40 +02:00
munja
bb89184212 fix: missing dependency in mv_deleteviyafolder 2022-03-16 16:01:22 +00:00
Allan Bowe
56338caaca Merge pull request #198 from sasjs/server
feat: enabling delete file for sasjs/server
2022-03-15 17:41:24 +02:00
munja
d7e2ff8ac9 fix: diffs for format loads not showing in audit table 2022-03-15 15:20:25 +00:00
munja
582ec0a1f9 feat: enabling delete file for sasjs/server 2022-03-15 13:46:31 +00:00
Allan Bowe
53785f5644 Update README.md 2022-03-14 13:44:13 +00:00
Allan Bowe
a8acadb8f1 Merge pull request #197 from sasjs/devops
gitpod & git hook updates
2022-03-11 23:25:20 +02:00
Allan Bowe
23dbda302e fix: ensuring pre-commit fails when sasjs lint fails 2022-03-11 21:24:34 +00:00
Allan Bowe
7e7ab4275d fix: gitpod launching sasjs 2022-03-11 21:23:52 +00:00
Allan Bowe
a455a3d98d Merge pull request #196 from sasjs/delfile
feat: adding new mf_deletefile macro (and test)
2022-03-11 17:20:34 +02:00
munja
588d987c25 fix: missing dependency in test 2022-03-11 15:14:54 +00:00
munja
8ffd06343a feat: adding new mf_deletefile macro (and test)
Also, update to mm_spkexport macro
2022-03-11 15:03:59 +00:00
25 changed files with 642 additions and 186 deletions

View File

@@ -1,5 +1,12 @@
#!/bin/bash #!/bin/bash
sasjs lint
# Ensure lint is passing
LINT=`sasjs lint`
if [[ "$LINT" != "✔ All matched files use @sasjs/lint code style!" ]]; then
echo "$LINT"
echo "To commit in spite of these warnings, use the -n parameter."
exit 1
fi
# Avoid commits to the master branch # Avoid commits to the master branch
BRANCH=`git rev-parse --abbrev-ref HEAD` BRANCH=`git rev-parse --abbrev-ref HEAD`

View File

@@ -1,7 +1,7 @@
tasks: tasks:
- init: | - init: npm install -g npm
nvm install --lts - command: npm i
npm i -g @sasjs/cli - command: npm i -g @sasjs/cli
image: image:
file: .gitpod.dockerfile file: .gitpod.dockerfile
@@ -24,4 +24,4 @@ github:
# add a "Review in Gitpod" button to pull requests (defaults to false) # add a "Review in Gitpod" button to pull requests (defaults to false)
addBadge: false addBadge: false
# add a label once the prebuild is ready to pull requests (defaults to false) # add a label once the prebuild is ready to pull requests (defaults to false)
addLabel: prebuilt-in-gitpod addLabel: prebuilt-in-gitpod

View File

@@ -217,6 +217,15 @@ If you find this library useful, please leave a [star](https://github.com/sasjs/
![](https://starchart.cc/sasjs/core.svg) ![](https://starchart.cc/sasjs/core.svg)
## Other SAS Repositories
The following repositories are also worth checking out:
* [chris-swenson/sasmacros](https://github.com/chris-swenson/sasmacros)
* [greg-wotton/sas-programs](https://github.com/greg-wootton/sas-programs)
* [KatjaGlassConsulting/SMILE-SmartSASMacros](https://github.com/KatjaGlassConsulting/SMILE-SmartSASMacros)
* [scottbass/sas](https://github.com/scottbass/SAS)
* [yabwon/sas_packages](https://github.com/yabwon/SAS_PACKAGES)
## Contributors ✨ ## Contributors ✨
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --> <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->

315
all.sas
View File

@@ -95,6 +95,37 @@ options noquotelenmax;
%mend mf_dedup; %mend mf_dedup;
/**
@file
@brief Deletes a physical file, if it exists
@details Usage:
%mf_writefile(&sasjswork/myfile.txt,l1=some content)
%mf_deletefile(&sasjswork/myfile.txt)
%mf_deletefile(&sasjswork/myfile.txt)
@param filepath Full path to the target file
@returns The return code from the fdelete() invocation
<h4> Related Macros </h4>
@li mf_deletefile.test.sas
@li mf_writefile.sas
@version 9.2
@author Allan Bowe
**/
%macro mf_deletefile(file
)/*/STORE SOURCE*/;
%local rc fref;
%let rc= %sysfunc(filename(fref,&file));
%if %sysfunc(fdelete(&fref)) ne 0 %then %put %sysfunc(sysmsg());
%let rc= %sysfunc(filename(fref));
%mend mf_deletefile;
/** /**
@file mf_existds.sas @file mf_existds.sas
@brief Checks whether a dataset OR a view exists. @brief Checks whether a dataset OR a view exists.
@@ -136,19 +167,17 @@ options noquotelenmax;
%put %mf_existfeature(PROCLUA); %put %mf_existfeature(PROCLUA);
@param feature the feature to detect. Leave blank to list all in log. @param [in] feature The feature to detect.
@return output returns 1 or 0 (or -1 if not found) @return output returns 1 or 0 (or -1 if not found)
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mf_getplatform.sas @li mf_getplatform.sas
@version 8 @version 8
@author Allan Bowe @author Allan Bowe
**/ **/
/** @cond */ /** @cond */
%macro mf_existfeature(feature %macro mf_existfeature(feature
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%let feature=%upcase(&feature); %let feature=%upcase(&feature);
@@ -156,7 +185,11 @@ options noquotelenmax;
%let platform=%mf_getplatform(); %let platform=%mf_getplatform();
%if &feature= %then %do; %if &feature= %then %do;
%put Supported features: PROCLUA; %put No feature was requested for detection;
%end;
%else %if &feature=COLCONSTRAINTS %then %do;
%if %substr(&sysver,1,1)=4 %then 0;
%else 1;
%end; %end;
%else %if &feature=PROCLUA %then %do; %else %if &feature=PROCLUA %then %do;
/* https://blogs.sas.com/content/sasdummy/2015/08/03/using-lua-within-your-sas-programs */ /* https://blogs.sas.com/content/sasdummy/2015/08/03/using-lua-within-your-sas-programs */
@@ -170,8 +203,8 @@ options noquotelenmax;
%put &sysmacroname: &feature not found; %put &sysmacroname: &feature not found;
%end; %end;
%mend mf_existfeature; %mend mf_existfeature;
/** @endcond */
/** @endcond *//** /**
@file @file
@brief Checks whether a fileref exists @brief Checks whether a fileref exists
@details You can probably do without this macro as it is just a one liner. @details You can probably do without this macro as it is just a one liner.
@@ -2161,7 +2194,7 @@ Usage:
%end; %end;
/* Stored Process Server web app context */ /* Stored Process Server web app context */
%if %symexist(_metaperson) %if %symexist(_METAFOLDER)
or "&SYSPROCESSNAME "="Compute Server " or "&SYSPROCESSNAME "="Compute Server "
or &mode=INCLUDE or &mode=INCLUDE
%then %do; %then %do;
@@ -2237,12 +2270,14 @@ Usage:
/* send response in SASjs JSON format */ /* send response in SASjs JSON format */
data _null_; data _null_;
file _webout mod lrecl=32000 encoding='utf-8'; file _webout mod lrecl=32000 encoding='utf-8';
length msg $32767 ; length msg syswarningtext syserrortext $32767 ;
sasdatetime=datetime(); sasdatetime=datetime();
msg=symget('msg'); msg=symget('msg');
%if &logline>0 %then %do; %if &logline>0 %then %do;
msg=cats(msg,'\n\nLog Extract:\n',symget('logmsg')); msg=cats(msg,'\n\nLog Extract:\n',symget('logmsg'));
%end; %end;
/* escape the escapes */
msg=tranwrd(msg,'\','\\');
/* escape the quotes */ /* escape the quotes */
msg=tranwrd(msg,'"','\"'); msg=tranwrd(msg,'"','\"');
/* ditch the CRLFs as chrome complains */ /* ditch the CRLFs as chrome complains */
@@ -2336,7 +2371,8 @@ Usage:
%end; %end;
%mend mp_abort; %mend mp_abort;
/** @endcond *//** /** @endcond */
/**
@file @file
@brief Append (concatenate) two or more files. @brief Append (concatenate) two or more files.
@details Will append one more more `appendrefs` (filerefs) to a `baseref`. @details Will append one more more `appendrefs` (filerefs) to a `baseref`.
@@ -3166,7 +3202,7 @@ run;
proc compare proc compare
base=&scopeds(where=(upcase(name) not in (%mf_getquotedstr(&ilist)))) base=&scopeds(where=(upcase(name) not in (%mf_getquotedstr(&ilist))))
compare=&ds; compare=&ds noprint;
run; run;
%if &sysinfo=0 %then %do; %if &sysinfo=0 %then %do;
@@ -7918,8 +7954,8 @@ run;
%mend mp_guesspk;/** %mend mp_guesspk;/**
@file @file
@brief Returns a unique hash for a dataset @brief Returns a unique hash for a dataset
@details Ignores metadata attributes, used only to hash values. Compared @details Ignores metadata attributes, used only to hash values. If used to
datasets must be in the same order. compare datasets, they must have their columns and rows in the same order.
%mp_hashdataset(sashelp.class,outds=myhash) %mp_hashdataset(sashelp.class,outds=myhash)
@@ -7934,7 +7970,10 @@ run;
@li mf_getattrn.sas @li mf_getattrn.sas
@li mf_getuniquename.sas @li mf_getuniquename.sas
@li mf_getvarlist.sas @li mf_getvarlist.sas
@li mf_getvartype.sas @li mp_md5.sas
<h4> Related Files </h4>
@li mp_hashdataset.test.sas
@param [in] libds dataset to hash @param [in] libds dataset to hash
@param [in] salt= Provide a salt (could be, for instance, the dataset name) @param [in] salt= Provide a salt (could be, for instance, the dataset name)
@@ -7952,51 +7991,52 @@ run;
%macro mp_hashdataset( %macro mp_hashdataset(
libds, libds,
outds=, outds=work._data_,
salt=, salt=,
iftrue=%str(1=1) iftrue=%str(1=1)
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%if not(%eval(%unquote(&iftrue))) %then %return; %local keyvar /* roll up the md5 */
prevkeyvar /* retain prev record md5 */
lastvar /* last var in input ds */
cvars nvars;
%if %mf_getattrn(&libds,NLOBS)=0 %then %do; %if not(%eval(%unquote(&iftrue))) %then %return;
%put %str(WARN)ING: Dataset &libds is empty, or is not a dataset;
%end; /* avoid naming conflict for hash key vars */
%else %if %mf_getattrn(&libds,NLOBS)<0 %then %do; %let keyvar=%mf_getuniquename();
%put %str(ERR)OR: Dataset &libds is not a dataset; %let prevkeyvar=%mf_getuniquename();
%end; %let lastvar=%mf_getuniquename();
%else %do;
%local keyvar /* roll up the md5 */ %if %mf_getattrn(&libds,NLOBS)=0 %then %do;
prevkeyvar /* retain prev record md5 */ data &outds;
lastvar /* last var in input ds */ length hashkey $32;
varlist var i; retain hashkey "%sysfunc(md5(%str(&salt)),$hex32.)";
/* avoid naming conflict for hash key vars */ output;
%let keyvar=%mf_getuniquename(); stop;
%let prevkeyvar=%mf_getuniquename(); run;
%let lastvar=%mf_getuniquename(); %put &sysmacroname: Dataset &libds is empty, or is not a dataset;
%let varlist=%mf_getvarlist(&libds); %put &sysmacroname: hashkey of &outds is based on salt (&salt) only;
data &outds(rename=(&keyvar=hashkey) keep=&keyvar); %end;
length &prevkeyvar &keyvar $32; %else %if %mf_getattrn(&libds,NLOBS)<0 %then %do;
retain &prevkeyvar "%sysfunc(md5(%str(&salt)),$hex32.)"; %put %str(ERR)OR: Dataset &libds is not a dataset;
set &libds end=&lastvar; %end;
/* hash should include previous row */ %else %do;
&keyvar=put(md5(&prevkeyvar data &outds(rename=(&keyvar=hashkey) keep=&keyvar)/nonote2err;
/* loop every column, hashing every individual value */ length &prevkeyvar &keyvar $32;
%do i=1 %to %sysfunc(countw(&varlist)); retain &prevkeyvar "%sysfunc(md5(%str(&salt)),$hex32.)";
%let var=%scan(&varlist,&i,%str( )); set &libds end=&lastvar;
%if %mf_getvartype(&libds,&var)=C %then %do; /* hash should include previous row */
!!put(md5(trim(&var)),$hex32.) &keyvar=%mp_md5(
%end; cvars=%mf_getvarlist(&libds,typefilter=C) &prevkeyvar,
%else %do; nvars=%mf_getvarlist(&libds,typefilter=N)
!!put(md5(trim(put(&var*1,binary64.))),$hex32.) );
%end; &prevkeyvar=&keyvar;
%end; if &lastvar then output;
),$hex32.); run;
&prevkeyvar=&keyvar; %end;
if &lastvar then output; %mend mp_hashdataset;
run; /**
%end;
%mend mp_hashdataset;/**
@file @file
@brief Performs a wrapped \%include @brief Performs a wrapped \%include
@details This macro wrapper is necessary if you need your included code to @details This macro wrapper is necessary if you need your included code to
@@ -8381,8 +8421,15 @@ options
prxchange('s/'!!'0A'x!!'/\n/',-1, prxchange('s/'!!'0A'x!!'/\n/',-1,
prxchange('s/'!!'0D'x!!'/\r/',-1, prxchange('s/'!!'0D'x!!'/\r/',-1,
prxchange('s/'!!'09'x!!'/\t/',-1, prxchange('s/'!!'09'x!!'/\t/',-1,
prxchange('s/'!!'00'x!!'/\\u0000/',-1, /* NUL */
prxchange('s/'!!'0E'x!!'/\\u000E/',-1, /* SS */
prxchange('s/'!!'0F'x!!'/\\u000F/',-1, /* SF */
prxchange('s/'!!'01'x!!'/\\u0001/',-1, /* SOH */
prxchange('s/'!!'02'x!!'/\\u0002/',-1, /* STX */
prxchange('s/'!!'02'x!!'/\\u0010/',-1, /* DLE */
prxchange('s/'!!'11'x!!'/\\u0011/',-1, /* DC1 */
prxchange('s/\\/\\\\/',-1,&&name&i) prxchange('s/\\/\\\\/',-1,&&name&i)
)))))!!'"'; ))))))))))))!!'"';
%end; %end;
%end; %end;
run; run;
@@ -8737,7 +8784,7 @@ run;
* First, extract only relevant formats from the catalog * First, extract only relevant formats from the catalog
*/ */
proc sql noprint; proc sql noprint;
select distinct fmtname into: fmtlist separated by ' ' from &libds; select distinct upcase(fmtname) into: fmtlist separated by ' ' from &libds;
%mp_cntlout(libcat=&libcat,fmtlist=&fmtlist,cntlout=&base_fmts) %mp_cntlout(libcat=&libcat,fmtlist=&fmtlist,cntlout=&base_fmts)
@@ -8747,8 +8794,11 @@ select distinct fmtname into: fmtlist separated by ' ' from &libds;
*/ */
%mddl_sas_cntlout(libds=&template) %mddl_sas_cntlout(libds=&template)
data &inlibds; data &inlibds;
length &delete_col $3;
if 0 then set &template; if 0 then set &template;
set &libds; set &libds;
if &delete_col='' then &delete_col='No';
fmtname=upcase(fmtname);
if missing(type) then do; if missing(type) then do;
if substr(fmtname,1,1)='$' then type='C'; if substr(fmtname,1,1)='$' then type='C';
else type='N'; else type='N';
@@ -8759,7 +8809,6 @@ data &inlibds;
end; end;
run; run;
/** /**
* Identify new records * Identify new records
*/ */
@@ -8866,7 +8915,7 @@ options ibufsize=&ibufsize;
%end; %end;
%mp_storediffs(&libcat-FC %mp_storediffs(&libcat-FC
,&inlibds ,&base_fmts
,FMTNAME START ,FMTNAME START
,delds=&outds_del ,delds=&outds_del
,modds=&outds_mod ,modds=&outds_mod
@@ -13322,8 +13371,8 @@ run;
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_abort.sas @li mp_abort.sas
@param libref the libref (not name) of the metadata library @param [in] libref The libref (not name) of the metadata library
@param mAbort= If not assigned, HARD will call %mp_abort(), SOFT will @param [in] mAbort= If not assigned, HARD will call %mp_abort(), SOFT will
silently return silently return
@returns libname statement @returns libname statement
@@ -13337,11 +13386,11 @@ run;
libref libref
,mAbort=HARD ,mAbort=HARD
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local mp_abort msg;
%let mp_abort=0;
%if %sysfunc(libref(&libref)) %then %do; %if %sysfunc(libref(&libref)) %then %do;
%local mp_abort msg; %let mp_abort=0;
data _null_; data _null_;
length liburi LibName $200; length liburi LibName msg $200;
call missing(of _all_); call missing(of _all_);
nobj=metadata_getnobj("omsobj:SASLibrary?@Libref='&libref'",1,liburi); nobj=metadata_getnobj("omsobj:SASLibrary?@Libref='&libref'",1,liburi);
if nobj=1 then do; if nobj=1 then do;
@@ -13355,7 +13404,24 @@ run;
* not always helpful though. One example, previously received: * not always helpful though. One example, previously received:
* NOTE: Libref XX refers to the same library metadata as libref XX. * NOTE: Libref XX refers to the same library metadata as libref XX.
*/ */
call symputx('msg',sysmsg(),'l'); msg=sysmsg();
if msg=:'ERROR: Libref SAVE is not assigned.' then do;
msg=catx(" ",
"Could not assign %upcase(&libref).",
"Please check metadata permissions! Libname:",libname,
"Liburi:",liburi
);
end;
else if msg="ERROR: User does not have appropriate authorization "!!
"level for library SAVE."
then do;
msg=catx(" ",
"ERROR: User does not have appropriate authorization level",
"for library %upcase(&libref), libname:",libname,
"Liburi:",liburi
);
end;
call symputx('msg',msg,'l');
if "&mabort"='HARD' then call symputx('mp_abort',1,'l'); if "&mabort"='HARD' then call symputx('mp_abort',1,'l');
end; end;
else do; else do;
@@ -13374,22 +13440,18 @@ run;
end; end;
run; run;
%if &mp_abort=1 %then %do; %put NOTE: &msg;
%mp_abort(iftrue= (&mp_abort=1)
,mac=mm_assignlib.sas
,msg=&msg
)
%return;
%end;
%else %if %length(&msg)>2 %then %do;
%put NOTE: &msg;
%return;
%end;
%end; %end;
%else %do; %else %do;
%put NOTE: Library &libref is already assigned; %put NOTE: Library &libref is already assigned;
%end; %end;
%mp_abort(iftrue= (&mp_abort=1)
,mac=mm_assignlib.sas
,msg=%superq(msg)
)
%mend mm_assignlib; %mend mm_assignlib;
/** /**
@file @file
@@ -14876,8 +14938,15 @@ data _null_;
put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, '; put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, ';
put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, '; put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, ';
put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, '; put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, ';
put ' prxchange(''s/''!!''00''x!!''/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/''!!''0E''x!!''/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/''!!''0F''x!!''/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/''!!''01''x!!''/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/''!!''02''x!!''/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/''!!''02''x!!''/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/''!!''11''x!!''/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) '; put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
put ' )))))!!''"''; '; put ' ))))))))))))!!''"''; ';
put ' %end; '; put ' %end; ';
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
@@ -17781,7 +17850,7 @@ filename __shake clear;
%let platform_object_path=%mf_loc(POF); %let platform_object_path=%mf_loc(POF);
%let ds=%mf_getuniquename(prefix=spkexportable); %let ds=%mf_getuniquename(prefix=spkexportable);
%mm_tree(root=%str(&metaloc) ,types=EXPORTABLE ,outds=&ds) %mm_tree(root=%str(&metaloc),types=EXPORTABLE ,outds=&ds)
%if %mf_isblank(&outref)=1 %then %let outref=%mf_getuniquefileref(); %if %mf_isblank(&outref)=1 %then %let outref=%mf_getuniquefileref();
@@ -17790,19 +17859,27 @@ data _null_;
file &outref lrecl=32767; file &outref lrecl=32767;
length str $32767; length str $32767;
if _n_=1 then do; if _n_=1 then do;
put "# Script generated by &sysuserid on %sysfunc(datetime(),datetime19.)";
put "cd ""&platform_object_path"" \"; put "cd ""&platform_object_path"" \";
put "; ./ExportPackage -host &host -port &port -user &mmxuser \"; put "; ./ExportPackage -host &host -port &port -user &mmxuser \";
put " -disableX11 -password &mmxpass \" put " -disableX11 -password &mmxpass \";
put " -package ""&cmdoutloc/&cmdoutname..spk"" \"; put " -package ""&cmdoutloc/&cmdoutname..spk"" \";
end; end;
/* exclude particular patterns from the exported SPK */ /* exclude particular patterns from the exported SPK */
%if "&excludevars" ne "0" %then %do; %if "&excludevars" ne "0" %then %do;
/* ignore top level folder else all subcontent will be exported regardless */
if _n_>1;
%do i=1 %to %sysfunc(countw(&excludevars)); %do i=1 %to %sysfunc(countw(&excludevars));
%let var=%scan(&excludevars,&i); %let var=%scan(&excludevars,&i);
if index(path,symget("&var")) ne 0; if _n_=1 then do;
length excludestr&i $1000;
retain excludestr&i;
excludestr&i=symget("&var");
putlog excludestr&i=;
putlog path=;
end;
if index(path,cats(excludestr&i))=0 and index(name,cats(excludestr&i))=0;
%end; %end;
/* ignore top level folder else all subcontent will be exported regardless */
if _n_>1;
%end; %end;
str=' -objects '!!cats('"',path,'/',name,"(",publictype,')" \'); str=' -objects '!!cats('"',path,'/',name,"(",publictype,')" \');
put str; put str;
@@ -18825,9 +18902,10 @@ run;
,mdebug=0 ,mdebug=0
); );
%local fname0 fname1 boundary fname statcd msg; %local fname0 fname1 fname2 boundary fname statcd msg;
%let fname0=%mf_getuniquefileref(); %let fname0=%mf_getuniquefileref();
%let fname1=%mf_getuniquefileref(); %let fname1=%mf_getuniquefileref();
%let fname2=%mf_getuniquefileref();
%let boundary=%mf_getuniquename(); %let boundary=%mf_getuniquename();
data _null_; data _null_;
@@ -18851,17 +18929,25 @@ data _null_;
end; end;
run; run;
data _null_;
file &fname1;
put "Content-Type: multipart/form-data; boundary=&boundary";
run;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
data _null_; data _null_;
infile &fname0; infile &fname0;
input; input;
put _infile_; put _infile_;
data _null_;
infile &fname1;
input;
put _infile_;
run; run;
%end; %end;
proc http method='POST' in=&fname0 out=&fname1 proc http method='POST' in=&fname0 headerin=&fname1 out=&fname2
url="&_sasjs_apiserverurl/SASjsApi/drive/file"; url="&_sasjs_apiserverurl/SASjsApi/drive/file";
headers "Content-Type"="multipart/form-data; boundary=&boundary";
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
debug level=1; debug level=1;
%end; %end;
@@ -18869,7 +18955,7 @@ run;
%let statcd=0; %let statcd=0;
data _null_; data _null_;
infile &fname1; infile &fname2;
input; input;
putlog _infile_; putlog _infile_;
if _infile_='{"status":"success"}' then call symputx('statcd',1,'l'); if _infile_='{"status":"success"}' then call symputx('statcd',1,'l');
@@ -18883,6 +18969,41 @@ run;
) )
%mend ms_createfile; %mend ms_createfile;
/**
@file
@brief Deletes a file from SASjs Drive
@details Deletes a file from SASjs Drive, if it exists.
Example:
filename stpcode temp;
data _null_;
file stpcode;
put '%put hello world;';
run;
%ms_createfile(/some/stored/program.sas, inref=stpcode)
%ms_deletefile(/some/stored/program.sas)
@param [in] driveloc The full path to the file in SASjs Drive
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
**/
%macro ms_deletefile(driveloc
,mdebug=0
);
proc http method='DELETE'
url="&_sasjs_apiserverurl/SASjsApi/drive/file?_filePath=&driveloc";
%if &mdebug=1 %then %do;
debug level=2;
%end;
run;
%mend ms_deletefile;
/** /**
@file @file
@brief Gets a file from SASjs Drive @brief Gets a file from SASjs Drive
@@ -18896,6 +19017,9 @@ run;
@param [out] outref= (msgetfil) The fileref to contain the file. @param [out] outref= (msgetfil) The fileref to contain the file.
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages @param [in] mdebug= (0) Set to 1 to enable DEBUG messages
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquename.sas
**/ **/
@@ -18904,15 +19028,21 @@ run;
,mdebug=0 ,mdebug=0
); );
filename &outref temp; /* use the recfm in a separate fileref to avoid issues with subsequent reads */
%local binaryfref floc;
%let binaryfref=%mf_getuniquefileref();
%let floc=%sysfunc(pathname(work))/%mf_getuniquename().txt;
filename &outref "&floc";
filename &binaryfref "&floc" recfm=n;
proc http method='GET' out=&outref proc http method='GET' out=&binaryfref
url="&_sasjs_apiserverurl/SASjsApi/drive/file?filePath=&driveloc"; url="&_sasjs_apiserverurl/SASjsApi/drive/file?_filePath=&driveloc";
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
debug level=2; debug level=2;
%end; %end;
run; run;
filename &binaryfref clear;
%mend ms_getfile; %mend ms_getfile;
/** /**
@@ -19107,6 +19237,7 @@ run;
data _null_; data _null_;
set &tempds; set &tempds;
if not (upcase(name) =:"DATA"); /* ignore temp datasets */ if not (upcase(name) =:"DATA"); /* ignore temp datasets */
if not (upcase(name)=:"_DATA_");
i+1; i+1;
call symputx(cats('wt',i),name,'l'); call symputx(cats('wt',i),name,'l');
call symputx('wtcnt',i,'l'); call symputx('wtcnt',i,'l');
@@ -20285,8 +20416,15 @@ data _null_;
put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, '; put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, ';
put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, '; put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, ';
put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, '; put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, ';
put ' prxchange(''s/''!!''00''x!!''/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/''!!''0E''x!!''/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/''!!''0F''x!!''/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/''!!''01''x!!''/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/''!!''02''x!!''/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/''!!''02''x!!''/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/''!!''11''x!!''/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) '; put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
put ' )))))!!''"''; '; put ' ))))))))))))!!''"''; ';
put ' %end; '; put ' %end; ';
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';
@@ -21048,6 +21186,7 @@ libname &libref1a clear;
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_abort.sas @li mp_abort.sas
@li mf_existds.sas
@li mf_getplatform.sas @li mf_getplatform.sas
@li mf_getuniquefileref.sas @li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas @li mf_getuniquelibref.sas

31
base/mf_deletefile.sas Normal file
View File

@@ -0,0 +1,31 @@
/**
@file
@brief Deletes a physical file, if it exists
@details Usage:
%mf_writefile(&sasjswork/myfile.txt,l1=some content)
%mf_deletefile(&sasjswork/myfile.txt)
%mf_deletefile(&sasjswork/myfile.txt)
@param filepath Full path to the target file
@returns The return code from the fdelete() invocation
<h4> Related Macros </h4>
@li mf_deletefile.test.sas
@li mf_writefile.sas
@version 9.2
@author Allan Bowe
**/
%macro mf_deletefile(file
)/*/STORE SOURCE*/;
%local rc fref;
%let rc= %sysfunc(filename(fref,&file));
%if %sysfunc(fdelete(&fref)) ne 0 %then %put %sysfunc(sysmsg());
%let rc= %sysfunc(filename(fref));
%mend mf_deletefile;

View File

@@ -9,19 +9,17 @@
%put %mf_existfeature(PROCLUA); %put %mf_existfeature(PROCLUA);
@param feature the feature to detect. Leave blank to list all in log. @param [in] feature The feature to detect.
@return output returns 1 or 0 (or -1 if not found) @return output returns 1 or 0 (or -1 if not found)
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mf_getplatform.sas @li mf_getplatform.sas
@version 8 @version 8
@author Allan Bowe @author Allan Bowe
**/ **/
/** @cond */ /** @cond */
%macro mf_existfeature(feature %macro mf_existfeature(feature
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%let feature=%upcase(&feature); %let feature=%upcase(&feature);
@@ -29,7 +27,11 @@
%let platform=%mf_getplatform(); %let platform=%mf_getplatform();
%if &feature= %then %do; %if &feature= %then %do;
%put Supported features: PROCLUA; %put No feature was requested for detection;
%end;
%else %if &feature=COLCONSTRAINTS %then %do;
%if %substr(&sysver,1,1)=4 %then 0;
%else 1;
%end; %end;
%else %if &feature=PROCLUA %then %do; %else %if &feature=PROCLUA %then %do;
/* https://blogs.sas.com/content/sasdummy/2015/08/03/using-lua-within-your-sas-programs */ /* https://blogs.sas.com/content/sasdummy/2015/08/03/using-lua-within-your-sas-programs */
@@ -43,5 +45,4 @@
%put &sysmacroname: &feature not found; %put &sysmacroname: &feature not found;
%end; %end;
%mend mf_existfeature; %mend mf_existfeature;
/** @endcond */
/** @endcond */

View File

@@ -85,7 +85,7 @@
%end; %end;
/* Stored Process Server web app context */ /* Stored Process Server web app context */
%if %symexist(_metaperson) %if %symexist(_METAFOLDER)
or "&SYSPROCESSNAME "="Compute Server " or "&SYSPROCESSNAME "="Compute Server "
or &mode=INCLUDE or &mode=INCLUDE
%then %do; %then %do;
@@ -161,12 +161,14 @@
/* send response in SASjs JSON format */ /* send response in SASjs JSON format */
data _null_; data _null_;
file _webout mod lrecl=32000 encoding='utf-8'; file _webout mod lrecl=32000 encoding='utf-8';
length msg $32767 ; length msg syswarningtext syserrortext $32767 ;
sasdatetime=datetime(); sasdatetime=datetime();
msg=symget('msg'); msg=symget('msg');
%if &logline>0 %then %do; %if &logline>0 %then %do;
msg=cats(msg,'\n\nLog Extract:\n',symget('logmsg')); msg=cats(msg,'\n\nLog Extract:\n',symget('logmsg'));
%end; %end;
/* escape the escapes */
msg=tranwrd(msg,'\','\\');
/* escape the quotes */ /* escape the quotes */
msg=tranwrd(msg,'"','\"'); msg=tranwrd(msg,'"','\"');
/* ditch the CRLFs as chrome complains */ /* ditch the CRLFs as chrome complains */
@@ -260,4 +262,4 @@
%end; %end;
%mend mp_abort; %mend mp_abort;
/** @endcond */ /** @endcond */

View File

@@ -106,7 +106,7 @@
proc compare proc compare
base=&scopeds(where=(upcase(name) not in (%mf_getquotedstr(&ilist)))) base=&scopeds(where=(upcase(name) not in (%mf_getquotedstr(&ilist))))
compare=&ds; compare=&ds noprint;
run; run;
%if &sysinfo=0 %then %do; %if &sysinfo=0 %then %do;

View File

@@ -1,8 +1,8 @@
/** /**
@file @file
@brief Returns a unique hash for a dataset @brief Returns a unique hash for a dataset
@details Ignores metadata attributes, used only to hash values. Compared @details Ignores metadata attributes, used only to hash values. If used to
datasets must be in the same order. compare datasets, they must have their columns and rows in the same order.
%mp_hashdataset(sashelp.class,outds=myhash) %mp_hashdataset(sashelp.class,outds=myhash)
@@ -17,7 +17,10 @@
@li mf_getattrn.sas @li mf_getattrn.sas
@li mf_getuniquename.sas @li mf_getuniquename.sas
@li mf_getvarlist.sas @li mf_getvarlist.sas
@li mf_getvartype.sas @li mp_md5.sas
<h4> Related Files </h4>
@li mp_hashdataset.test.sas
@param [in] libds dataset to hash @param [in] libds dataset to hash
@param [in] salt= Provide a salt (could be, for instance, the dataset name) @param [in] salt= Provide a salt (could be, for instance, the dataset name)
@@ -35,48 +38,48 @@
%macro mp_hashdataset( %macro mp_hashdataset(
libds, libds,
outds=, outds=work._data_,
salt=, salt=,
iftrue=%str(1=1) iftrue=%str(1=1)
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%if not(%eval(%unquote(&iftrue))) %then %return; %local keyvar /* roll up the md5 */
prevkeyvar /* retain prev record md5 */
lastvar /* last var in input ds */
cvars nvars;
%if %mf_getattrn(&libds,NLOBS)=0 %then %do; %if not(%eval(%unquote(&iftrue))) %then %return;
%put %str(WARN)ING: Dataset &libds is empty, or is not a dataset;
%end; /* avoid naming conflict for hash key vars */
%else %if %mf_getattrn(&libds,NLOBS)<0 %then %do; %let keyvar=%mf_getuniquename();
%put %str(ERR)OR: Dataset &libds is not a dataset; %let prevkeyvar=%mf_getuniquename();
%end; %let lastvar=%mf_getuniquename();
%else %do;
%local keyvar /* roll up the md5 */ %if %mf_getattrn(&libds,NLOBS)=0 %then %do;
prevkeyvar /* retain prev record md5 */ data &outds;
lastvar /* last var in input ds */ length hashkey $32;
varlist var i; retain hashkey "%sysfunc(md5(%str(&salt)),$hex32.)";
/* avoid naming conflict for hash key vars */ output;
%let keyvar=%mf_getuniquename(); stop;
%let prevkeyvar=%mf_getuniquename(); run;
%let lastvar=%mf_getuniquename(); %put &sysmacroname: Dataset &libds is empty, or is not a dataset;
%let varlist=%mf_getvarlist(&libds); %put &sysmacroname: hashkey of &outds is based on salt (&salt) only;
data &outds(rename=(&keyvar=hashkey) keep=&keyvar); %end;
length &prevkeyvar &keyvar $32; %else %if %mf_getattrn(&libds,NLOBS)<0 %then %do;
retain &prevkeyvar "%sysfunc(md5(%str(&salt)),$hex32.)"; %put %str(ERR)OR: Dataset &libds is not a dataset;
set &libds end=&lastvar; %end;
/* hash should include previous row */ %else %do;
&keyvar=put(md5(&prevkeyvar data &outds(rename=(&keyvar=hashkey) keep=&keyvar)/nonote2err;
/* loop every column, hashing every individual value */ length &prevkeyvar &keyvar $32;
%do i=1 %to %sysfunc(countw(&varlist)); retain &prevkeyvar "%sysfunc(md5(%str(&salt)),$hex32.)";
%let var=%scan(&varlist,&i,%str( )); set &libds end=&lastvar;
%if %mf_getvartype(&libds,&var)=C %then %do; /* hash should include previous row */
!!put(md5(trim(&var)),$hex32.) &keyvar=%mp_md5(
%end; cvars=%mf_getvarlist(&libds,typefilter=C) &prevkeyvar,
%else %do; nvars=%mf_getvarlist(&libds,typefilter=N)
!!put(md5(trim(put(&var*1,binary64.))),$hex32.) );
%end; &prevkeyvar=&keyvar;
%end; if &lastvar then output;
),$hex32.); run;
&prevkeyvar=&keyvar; %end;
if &lastvar then output; %mend mp_hashdataset;
run;
%end;
%mend mp_hashdataset;

View File

@@ -203,8 +203,15 @@
prxchange('s/'!!'0A'x!!'/\n/',-1, prxchange('s/'!!'0A'x!!'/\n/',-1,
prxchange('s/'!!'0D'x!!'/\r/',-1, prxchange('s/'!!'0D'x!!'/\r/',-1,
prxchange('s/'!!'09'x!!'/\t/',-1, prxchange('s/'!!'09'x!!'/\t/',-1,
prxchange('s/'!!'00'x!!'/\\u0000/',-1, /* NUL */
prxchange('s/'!!'0E'x!!'/\\u000E/',-1, /* SS */
prxchange('s/'!!'0F'x!!'/\\u000F/',-1, /* SF */
prxchange('s/'!!'01'x!!'/\\u0001/',-1, /* SOH */
prxchange('s/'!!'02'x!!'/\\u0002/',-1, /* STX */
prxchange('s/'!!'02'x!!'/\\u0010/',-1, /* DLE */
prxchange('s/'!!'11'x!!'/\\u0011/',-1, /* DC1 */
prxchange('s/\\/\\\\/',-1,&&name&i) prxchange('s/\\/\\\\/',-1,&&name&i)
)))))!!'"'; ))))))))))))!!'"';
%end; %end;
%end; %end;
run; run;

View File

@@ -134,7 +134,7 @@ run;
* First, extract only relevant formats from the catalog * First, extract only relevant formats from the catalog
*/ */
proc sql noprint; proc sql noprint;
select distinct fmtname into: fmtlist separated by ' ' from &libds; select distinct upcase(fmtname) into: fmtlist separated by ' ' from &libds;
%mp_cntlout(libcat=&libcat,fmtlist=&fmtlist,cntlout=&base_fmts) %mp_cntlout(libcat=&libcat,fmtlist=&fmtlist,cntlout=&base_fmts)
@@ -144,8 +144,11 @@ select distinct fmtname into: fmtlist separated by ' ' from &libds;
*/ */
%mddl_sas_cntlout(libds=&template) %mddl_sas_cntlout(libds=&template)
data &inlibds; data &inlibds;
length &delete_col $3;
if 0 then set &template; if 0 then set &template;
set &libds; set &libds;
if &delete_col='' then &delete_col='No';
fmtname=upcase(fmtname);
if missing(type) then do; if missing(type) then do;
if substr(fmtname,1,1)='$' then type='C'; if substr(fmtname,1,1)='$' then type='C';
else type='N'; else type='N';
@@ -156,7 +159,6 @@ data &inlibds;
end; end;
run; run;
/** /**
* Identify new records * Identify new records
*/ */
@@ -263,7 +265,7 @@ options ibufsize=&ibufsize;
%end; %end;
%mp_storediffs(&libcat-FC %mp_storediffs(&libcat-FC
,&inlibds ,&base_fmts
,FMTNAME START ,FMTNAME START
,delds=&outds_del ,delds=&outds_del
,modds=&outds_mod ,modds=&outds_mod

View File

@@ -13,8 +13,8 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_abort.sas @li mp_abort.sas
@param libref the libref (not name) of the metadata library @param [in] libref The libref (not name) of the metadata library
@param mAbort= If not assigned, HARD will call %mp_abort(), SOFT will @param [in] mAbort= If not assigned, HARD will call %mp_abort(), SOFT will
silently return silently return
@returns libname statement @returns libname statement
@@ -28,11 +28,11 @@
libref libref
,mAbort=HARD ,mAbort=HARD
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%local mp_abort msg;
%let mp_abort=0;
%if %sysfunc(libref(&libref)) %then %do; %if %sysfunc(libref(&libref)) %then %do;
%local mp_abort msg; %let mp_abort=0;
data _null_; data _null_;
length liburi LibName $200; length liburi LibName msg $200;
call missing(of _all_); call missing(of _all_);
nobj=metadata_getnobj("omsobj:SASLibrary?@Libref='&libref'",1,liburi); nobj=metadata_getnobj("omsobj:SASLibrary?@Libref='&libref'",1,liburi);
if nobj=1 then do; if nobj=1 then do;
@@ -46,7 +46,24 @@
* not always helpful though. One example, previously received: * not always helpful though. One example, previously received:
* NOTE: Libref XX refers to the same library metadata as libref XX. * NOTE: Libref XX refers to the same library metadata as libref XX.
*/ */
call symputx('msg',sysmsg(),'l'); msg=sysmsg();
if msg=:'ERROR: Libref SAVE is not assigned.' then do;
msg=catx(" ",
"Could not assign %upcase(&libref).",
"Please check metadata permissions! Libname:",libname,
"Liburi:",liburi
);
end;
else if msg="ERROR: User does not have appropriate authorization "!!
"level for library SAVE."
then do;
msg=catx(" ",
"ERROR: User does not have appropriate authorization level",
"for library %upcase(&libref), libname:",libname,
"Liburi:",liburi
);
end;
call symputx('msg',msg,'l');
if "&mabort"='HARD' then call symputx('mp_abort',1,'l'); if "&mabort"='HARD' then call symputx('mp_abort',1,'l');
end; end;
else do; else do;
@@ -65,20 +82,16 @@
end; end;
run; run;
%if &mp_abort=1 %then %do; %put NOTE: &msg;
%mp_abort(iftrue= (&mp_abort=1)
,mac=mm_assignlib.sas
,msg=&msg
)
%return;
%end;
%else %if %length(&msg)>2 %then %do;
%put NOTE: &msg;
%return;
%end;
%end; %end;
%else %do; %else %do;
%put NOTE: Library &libref is already assigned; %put NOTE: Library &libref is already assigned;
%end; %end;
%mp_abort(iftrue= (&mp_abort=1)
,mac=mm_assignlib.sas
,msg=%superq(msg)
)
%mend mm_assignlib; %mend mm_assignlib;

View File

@@ -236,8 +236,15 @@ data _null_;
put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, '; put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, ';
put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, '; put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, ';
put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, '; put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, ';
put ' prxchange(''s/''!!''00''x!!''/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/''!!''0E''x!!''/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/''!!''0F''x!!''/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/''!!''01''x!!''/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/''!!''02''x!!''/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/''!!''02''x!!''/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/''!!''11''x!!''/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) '; put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
put ' )))))!!''"''; '; put ' ))))))))))))!!''"''; ';
put ' %end; '; put ' %end; ';
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';

View File

@@ -102,7 +102,7 @@
%let platform_object_path=%mf_loc(POF); %let platform_object_path=%mf_loc(POF);
%let ds=%mf_getuniquename(prefix=spkexportable); %let ds=%mf_getuniquename(prefix=spkexportable);
%mm_tree(root=%str(&metaloc) ,types=EXPORTABLE ,outds=&ds) %mm_tree(root=%str(&metaloc),types=EXPORTABLE ,outds=&ds)
%if %mf_isblank(&outref)=1 %then %let outref=%mf_getuniquefileref(); %if %mf_isblank(&outref)=1 %then %let outref=%mf_getuniquefileref();
@@ -111,19 +111,27 @@ data _null_;
file &outref lrecl=32767; file &outref lrecl=32767;
length str $32767; length str $32767;
if _n_=1 then do; if _n_=1 then do;
put "# Script generated by &sysuserid on %sysfunc(datetime(),datetime19.)";
put "cd ""&platform_object_path"" \"; put "cd ""&platform_object_path"" \";
put "; ./ExportPackage -host &host -port &port -user &mmxuser \"; put "; ./ExportPackage -host &host -port &port -user &mmxuser \";
put " -disableX11 -password &mmxpass \" put " -disableX11 -password &mmxpass \";
put " -package ""&cmdoutloc/&cmdoutname..spk"" \"; put " -package ""&cmdoutloc/&cmdoutname..spk"" \";
end; end;
/* exclude particular patterns from the exported SPK */ /* exclude particular patterns from the exported SPK */
%if "&excludevars" ne "0" %then %do; %if "&excludevars" ne "0" %then %do;
/* ignore top level folder else all subcontent will be exported regardless */
if _n_>1;
%do i=1 %to %sysfunc(countw(&excludevars)); %do i=1 %to %sysfunc(countw(&excludevars));
%let var=%scan(&excludevars,&i); %let var=%scan(&excludevars,&i);
if index(path,symget("&var")) ne 0; if _n_=1 then do;
length excludestr&i $1000;
retain excludestr&i;
excludestr&i=symget("&var");
putlog excludestr&i=;
putlog path=;
end;
if index(path,cats(excludestr&i))=0 and index(name,cats(excludestr&i))=0;
%end; %end;
/* ignore top level folder else all subcontent will be exported regardless */
if _n_>1;
%end; %end;
str=' -objects '!!cats('"',path,'/',name,"(",publictype,')" \'); str=' -objects '!!cats('"',path,'/',name,"(",publictype,')" \');
put str; put str;

View File

@@ -4,11 +4,8 @@
"base", "base",
"ddl", "ddl",
"fcmp", "fcmp",
"meta",
"metax",
"server",
"viya",
"lua", "lua",
"server",
"tests/crossplatform", "tests/crossplatform",
"tests/ddl" "tests/ddl"
], ],
@@ -39,6 +36,7 @@
}, },
"appLoc": "/Public/temp/macrocore", "appLoc": "/Public/temp/macrocore",
"macroFolders": [ "macroFolders": [
"viya",
"tests/viyaonly" "tests/viyaonly"
], ],
"programFolders": [], "programFolders": [],
@@ -58,6 +56,8 @@
}, },
"appLoc": "/Shared Data/temp/macrocore", "appLoc": "/Shared Data/temp/macrocore",
"macroFolders": [ "macroFolders": [
"meta",
"metax",
"tests/sas9only" "tests/sas9only"
], ],
"programFolders": [], "programFolders": [],
@@ -78,6 +78,7 @@
}, },
"appLoc": "/sasjs/core", "appLoc": "/sasjs/core",
"macroFolders": [ "macroFolders": [
"server",
"tests/serveronly" "tests/serveronly"
], ],
"programFolders": [], "programFolders": [],
@@ -92,6 +93,10 @@
"serverType": "SAS9", "serverType": "SAS9",
"appLoc": "dummy", "appLoc": "dummy",
"macroFolders": [ "macroFolders": [
"meta",
"metax",
"server",
"viya",
"tests/sas9only", "tests/sas9only",
"tests/viyaonly" "tests/viyaonly"
] ]
@@ -102,6 +107,7 @@
"serverType": "SASVIYA", "serverType": "SASVIYA",
"appLoc": "/Public/temp/macrocore", "appLoc": "/Public/temp/macrocore",
"macroFolders": [ "macroFolders": [
"viya",
"tests/viyaonly" "tests/viyaonly"
], ],
"deployConfig": { "deployConfig": {
@@ -110,4 +116,4 @@
"contextName": "SAS Job Execution compute context" "contextName": "SAS Job Execution compute context"
} }
] ]
} }

View File

@@ -29,9 +29,10 @@
,mdebug=0 ,mdebug=0
); );
%local fname0 fname1 boundary fname statcd msg; %local fname0 fname1 fname2 boundary fname statcd msg;
%let fname0=%mf_getuniquefileref(); %let fname0=%mf_getuniquefileref();
%let fname1=%mf_getuniquefileref(); %let fname1=%mf_getuniquefileref();
%let fname2=%mf_getuniquefileref();
%let boundary=%mf_getuniquename(); %let boundary=%mf_getuniquename();
data _null_; data _null_;
@@ -55,17 +56,25 @@ data _null_;
end; end;
run; run;
data _null_;
file &fname1;
put "Content-Type: multipart/form-data; boundary=&boundary";
run;
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
data _null_; data _null_;
infile &fname0; infile &fname0;
input; input;
put _infile_; put _infile_;
data _null_;
infile &fname1;
input;
put _infile_;
run; run;
%end; %end;
proc http method='POST' in=&fname0 out=&fname1 proc http method='POST' in=&fname0 headerin=&fname1 out=&fname2
url="&_sasjs_apiserverurl/SASjsApi/drive/file"; url="&_sasjs_apiserverurl/SASjsApi/drive/file";
headers "Content-Type"="multipart/form-data; boundary=&boundary";
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
debug level=1; debug level=1;
%end; %end;
@@ -73,7 +82,7 @@ run;
%let statcd=0; %let statcd=0;
data _null_; data _null_;
infile &fname1; infile &fname2;
input; input;
putlog _infile_; putlog _infile_;
if _infile_='{"status":"success"}' then call symputx('statcd',1,'l'); if _infile_='{"status":"success"}' then call symputx('statcd',1,'l');

35
server/ms_deletefile.sas Normal file
View File

@@ -0,0 +1,35 @@
/**
@file
@brief Deletes a file from SASjs Drive
@details Deletes a file from SASjs Drive, if it exists.
Example:
filename stpcode temp;
data _null_;
file stpcode;
put '%put hello world;';
run;
%ms_createfile(/some/stored/program.sas, inref=stpcode)
%ms_deletefile(/some/stored/program.sas)
@param [in] driveloc The full path to the file in SASjs Drive
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
**/
%macro ms_deletefile(driveloc
,mdebug=0
);
proc http method='DELETE'
url="&_sasjs_apiserverurl/SASjsApi/drive/file?_filePath=&driveloc";
%if &mdebug=1 %then %do;
debug level=2;
%end;
run;
%mend ms_deletefile;

View File

@@ -11,6 +11,9 @@
@param [out] outref= (msgetfil) The fileref to contain the file. @param [out] outref= (msgetfil) The fileref to contain the file.
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages @param [in] mdebug= (0) Set to 1 to enable DEBUG messages
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquename.sas
**/ **/
@@ -19,14 +22,20 @@
,mdebug=0 ,mdebug=0
); );
filename &outref temp; /* use the recfm in a separate fileref to avoid issues with subsequent reads */
%local binaryfref floc;
%let binaryfref=%mf_getuniquefileref();
%let floc=%sysfunc(pathname(work))/%mf_getuniquename().txt;
filename &outref "&floc";
filename &binaryfref "&floc" recfm=n;
proc http method='GET' out=&outref proc http method='GET' out=&binaryfref
url="&_sasjs_apiserverurl/SASjsApi/drive/file?filePath=&driveloc"; url="&_sasjs_apiserverurl/SASjsApi/drive/file?_filePath=&driveloc";
%if &mdebug=1 %then %do; %if &mdebug=1 %then %do;
debug level=2; debug level=2;
%end; %end;
run; run;
filename &binaryfref clear;
%mend ms_getfile; %mend ms_getfile;

View File

@@ -114,6 +114,7 @@
data _null_; data _null_;
set &tempds; set &tempds;
if not (upcase(name) =:"DATA"); /* ignore temp datasets */ if not (upcase(name) =:"DATA"); /* ignore temp datasets */
if not (upcase(name)=:"_DATA_");
i+1; i+1;
call symputx(cats('wt',i),name,'l'); call symputx(cats('wt',i),name,'l');
call symputx('wtcnt',i,'l'); call symputx('wtcnt',i,'l');

View File

@@ -0,0 +1,29 @@
/**
@file
@brief Testing mf_deletefile.sas macro
<h4> SAS Macros </h4>
@li mf_deletefile.sas
@li mf_writefile.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
%let test1file=&sasjswork/myfile1.txt;
%mf_writefile(&test1file,l1=some content)
%mp_assert(
iftrue=(%sysfunc(fileexist(&test1file))=1),
desc=Check &test1file exists
)
%mp_assertscope(SNAPSHOT)
%mf_deletefile(&test1file)
%mp_assertscope(COMPARE)
%mp_assert(
iftrue=(%sysfunc(fileexist(&test1file))=0),
desc=Check &test1file no longer exists
)

View File

@@ -0,0 +1,60 @@
/**
@file
@brief Testing mp_hashdataset.sas macro
<h4> SAS Macros </h4>
@li mp_hashdataset.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
/* test 1 - regular DS */
data work.test;
set sashelp.vextfl;
missval=.;
misscval='';
run;
%mp_assertscope(SNAPSHOT)
%mp_hashdataset(test)
%mp_assertscope(COMPARE)
%mp_assert(
iftrue=(&syscc=0),
desc=Regular test works,
outds=work.test_results
)
%mp_hashdataset(test,outds=work.test2)
%mp_assert(
iftrue=(&syscc=0),
desc=hash with output runs without errors,
outds=work.test_results
)
%mp_assert(
iftrue=(%mf_nobs(work.test2)=1),
desc=output has 1 row,
outds=work.test_results
)
data work.test3a;
set work.test;
stop;
run;
%mp_hashdataset(test3a,outds=work.test3b)
%mp_assert(
iftrue=(&syscc=0),
desc=hash with zero-row input runs without errors,
outds=work.test_results
)
%mp_assert(
iftrue=(%mf_nobs(work.test3b)=1),
desc=test 3 output has 1 row,
outds=work.test_results
)

View File

@@ -82,3 +82,12 @@ run;
desc=Test 1 - audit table updated, desc=Test 1 - audit table updated,
outds=work.test_results outds=work.test_results
) )
data work.difftest;
set perm.audit;
where is_diff=1;
run;
%mp_assert(
iftrue=(%mf_nobs(work.difftest)>0),
desc=Test 1 - diffs were found,
outds=work.test_results
)

View File

@@ -0,0 +1,61 @@
/**
@file
@brief Testing ms_deletefile.sas macro
<h4> SAS Macros </h4>
@li ms_createfile.sas
@li ms_deletefile.sas
@li ms_getfile.sas
@li mp_assert.sas
@li mp_assertscope.sas
**/
/* first make a remote file */
filename stpcode temp;
%let fname=%mf_getuniquename();
data _null_;
file stpcode;
put "data &fname;run;";
run;
%ms_createfile(/sasjs/tests/&fname..sas
,inref=stpcode
,mdebug=1
)
%ms_getfile(/sasjs/tests/&fname..sas,outref=testref)
%let test1=0;
data _null_;
infile testref;
input;
call symputx('test1',_infile_);
run;
%mp_assert(
iftrue=("&test1"="data &fname;run;"),
desc=Make sure the file was created,
outds=work.test_results
)
%mp_assertscope(SNAPSHOT)
%ms_deletefile(/sasjs/tests/&fname..sas,mdebug=1)
%mp_assertscope(COMPARE)
%ms_getfile(/sasjs/tests/&fname..sas,outref=testref2)
%let test2=0;
data _null_;
infile testref2;
input;
call symputx('test2',_infile_);
run;
%mp_assert(
iftrue=("&test2"="%str(Err)or: File does not exist."),
desc=Make sure the file was deleted,
outds=work.test_results
)

View File

@@ -380,8 +380,15 @@ data _null_;
put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, '; put ' prxchange(''s/''!!''0A''x!!''/\n/'',-1, ';
put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, '; put ' prxchange(''s/''!!''0D''x!!''/\r/'',-1, ';
put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, '; put ' prxchange(''s/''!!''09''x!!''/\t/'',-1, ';
put ' prxchange(''s/''!!''00''x!!''/\\u0000/'',-1, /* NUL */ ';
put ' prxchange(''s/''!!''0E''x!!''/\\u000E/'',-1, /* SS */ ';
put ' prxchange(''s/''!!''0F''x!!''/\\u000F/'',-1, /* SF */ ';
put ' prxchange(''s/''!!''01''x!!''/\\u0001/'',-1, /* SOH */ ';
put ' prxchange(''s/''!!''02''x!!''/\\u0002/'',-1, /* STX */ ';
put ' prxchange(''s/''!!''02''x!!''/\\u0010/'',-1, /* DLE */ ';
put ' prxchange(''s/''!!''11''x!!''/\\u0011/'',-1, /* DC1 */ ';
put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) '; put ' prxchange(''s/\\/\\\\/'',-1,&&name&i) ';
put ' )))))!!''"''; '; put ' ))))))))))))!!''"''; ';
put ' %end; '; put ' %end; ';
put ' %end; '; put ' %end; ';
put ' run; '; put ' run; ';

View File

@@ -25,6 +25,7 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mp_abort.sas @li mp_abort.sas
@li mf_existds.sas
@li mf_getplatform.sas @li mf_getplatform.sas
@li mf_getuniquefileref.sas @li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas @li mf_getuniquelibref.sas