sasjs / cli

Command line interface for creating, compiling, and building SAS® projects
https://cli.sasjs.io
MIT License
37 stars 5 forks source link

sasjs fs compile {localFolder} {outputProgram} #1262

Closed allanbowe closed 2 years ago

allanbowe commented 2 years ago

Sometimes (well - oftentimes) when running SAS remotely, it is necessary to configure files (code, data, config) on the server filesystem.

In the absence of ssh or ftp this usually involves a manual process with a client tool or web app.

The purpose of this new command (sasjs fs compile) will be to generate a SAS program that contains the contents of a local directory. By simply running this program in SAS Studio (or wherever), the developer can create a remote copy of a local filesystem.

The generated program will have the following components:

  1. Target Directory switch
  2. Dependent SAS Macros
  3. Directory creation section
  4. Files creation section

In terms of implementation, all the necessary logic should be in the @sasjs/utils repo, so that the functionality may be re-used by SASjs Server and the SASjs VS Code Extension.

The syntax will be as follows:

sasjs fs compile {localFolder} {outputProgram} 

Target Directory Switch

The {outputProgram} will NOT contain details of the target folder - allowing a folder to be initially compiled, then subsequently deployed to one or more different target locations.

The implementation is simply to have the following code at the start of the program:

%global fsTarget;
%let compiled_fsTarget=%sysfunc(pathname(work));
%let fsTarget=%sysfunc(coalescec(&fsTarget,&compiled_fsTarget));
options nobomfile;

This will mean that a compiled FS will be deployed to the temporary SAS WORK folder if an fsTarget variable has not been supplied.

Dependent SAS Macros

The following macros should be compiled into the start of the program:

Directory Creation

A unique set of subdirectories should be extracted, and the following code executed for each child:

%mf_mkdir(&fsTarget/${SUBDIR})

Files Creation

Each file must be base64 encoded in a similar way that we do for sasjs web.

The generated SAS for each input file will be as follows:

filename _in64 temp lrecl=99999999;
data _null_;
  file _in64;
  ${COMPILED_CONTENT}
run;
filename _out64 "&fsTarget/${SUBDIR}";
/* convert from base64 */
data _null_;
  length filein 8 fileout 8;
  filein = fopen("_in64",'I',4,'B');
  fileout = fopen("_out64",'A',1,'B');
  char= '20'x;
  do while(fread(filein)=0);
    length raw $4 ;
    do i=1 to 4;
      rc=fget(filein,char,1);
      substr(raw,i,1)=char;
    end;
    rc = fput(fileout, input(raw,$base64X4.));
    rc =fwrite(fileout);
  end;
  rc = fclose(filein);
  rc = fclose(fileout);
run;
filename _in64 clear;
filename _out64 clear;
sasjsbot commented 2 years ago

:tada: This issue has been resolved in version 3.20.0 :tada:

The release is available on:

Your semantic-release bot :package::rocket: