├── LICENSE ├── src └── cls │ └── CacheUpdater │ ├── TextServices.cls │ ├── Task.cls │ └── UDL.cls └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 eduard93 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /src/cls/CacheUpdater/TextServices.cls: -------------------------------------------------------------------------------- 1 | Class CacheUpdater.TextServices Extends %Compiler.UDL.TextServices 2 | { 3 | 4 | /// This method takes a namespace an integer subscripted array containing lines of text which represent a 5 | /// class definition in the UDL class definition language. Subscript value 0 should contain a count 6 | /// of lines of text which are defined as subscript value 1 ... n in the array 7 | /// 8 | /// Unlike %Compiler.UDL.TextServices saves classes with grammar errors. Taken from Atelier API 9 | /// 10 | /// It is important to realize that this method will replace the existing class definition if present and therefore 11 | /// must contain a full representation of the class as can be obtained by calling the GetClassXXX() method(s) in 12 | /// this class. Note: The name of the class is derived from the name of the class defined within the text 13 | ClassMethod SetTextFromArray(pNamespace As %String = {$namespace}, pClassname As %String, ByRef pDocumentArray As %String) As %Status 14 | { 15 | #dim tSC,tStatus As %Status = $$$OK 16 | #dim e As %Exception.AbstractException 17 | 18 | #dim tErrList,tOneErr As %String 19 | #dim tResultCode,tI As %Integer 20 | 21 | Try { 22 | #; TODO: make sure pClassname and classname within the text match, else throw an error 23 | #; Remember pClassname has .cls extension! 24 | 25 | #; Swap namespace if necessary 26 | If pNamespace'=$namespace new $namespace Set $namespace=pNamespace 27 | 28 | #; Save the definition (just saves, doesn't compile) 29 | Set tFlags=16777216 ; 0x01000000 = IPARSE_UDL_SAVEWITHERRORS save even if parse errors 30 | 31 | Set tResultCode=$compile(pDocumentArray,128,tErrList,,,tFlags) 32 | If tResultCode { 33 | For tI=1:1:$ll(tErrList) { 34 | Set tOneErr = $list(tErrList,tI),tStatus=$$$ERROR($$$ClassSaveError,$li(tOneErr,4),$li(tOneErr,1),$li(tOneErr,2),$li(tOneErr,6)) 35 | If tSC=$$$OK { 36 | Set tSC=tStatus 37 | } else { 38 | Set tSC=$$$ADDSC(tSC,tStatus) 39 | } 40 | } 41 | } 42 | } Catch (e) { 43 | Set tSC=e.AsStatus() 44 | } 45 | Quit tSC 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitHubUpdater 2 | Sync GitHub repositories into InterSystems Cache. 3 | 4 | Installation 5 | ----------- 6 | 7 | 1. Download the latest Release .xml file and import it into Caché (any namespace, further referred to as {Namespace}). 8 | 9 | Usage 10 | ----------- 11 | 12 | Call 13 | 14 | w ##class(CacheUpdater.Task).Update("Owner", "Repository", "Branch", "Username", "Password", "Namespace") 15 | 16 | to download and compile classes from the Github repo. 17 | 18 | Where
19 | Owner - The name of the repository owner.
20 | Repository - The name of the repository.
21 | Branch - The name of the commit/branch/tag. If skipped the repository’s default branch (usually master) would be used.
22 | Username - GitHub user, who has access to repository. Optional for public repositories.
23 | Password - GitHub password, corresponding to Username. Optional for public repositories.
24 | Note, that with Username, you can make up to 5,000 requests per hour. 25 | For unauthenticated requests, the rate limit allows to make up to 60 requests per hour. 26 | Unauthenticated requests are associated with an IP address.
27 | Namespace - Namespace, where to download and compile repository.
28 | For example in the repository: https://github.com/intersystems-ru/Cache-MDX2JSON
29 | Owner - intersystems-ru, Repository - Cache-MDX2JSON.
30 | 31 | OR 32 | 33 | create task for syncing GitHub repository → Cache instance do the following: 34 | 35 | 1. Go to SMP → System Operation → Task Manager → New Task 36 | 2. Set Name as desired 37 | 3. Set Namespace to run task in to {Namespace} 38 | 4. Set Task type to GitHub Update 39 | 5. Set GitHubURL to a valid GitHub repository, eg: https://github.com/intersystems-ru/Cache-MDX2JSON 40 | 7. Set Namespace to a Namespace you want to download GitHub repository to 41 | 8. Optionally provide Username, Password (for private repos or very frequent updates). 42 | 9. Set up the Branch you need. Possible values are names of commit/branch/tag 43 | 8. Set other parameters as desired and finish creation of the task 44 | 45 | After task runs at least once you will get GitHubURL repository contents in Namespace 46 | 47 | 48 | 49 | Continuous Integration 50 | ----------- 51 | 52 | If you want more functionality check out [CacheGitHubCI](https://github.com/intersystems-ru/CacheGitHubCI) project. 53 | -------------------------------------------------------------------------------- /src/cls/CacheUpdater/Task.cls: -------------------------------------------------------------------------------- 1 | Class CacheUpdater.Task Extends (%SYS.Task.Definition, CacheUpdater.UDL) 2 | { 3 | 4 | Parameter TaskName = "GitHub Update"; 5 | 6 | /// Repository URL, like https://github.com/intersystems-ru/Cache-MDX2JSON 7 | /// Increased to 500 to support long urls 8 | Property GitHubURL As %String(MAXLEN = 500); 9 | 10 | /// GitHub user, who has access to repository. Optional for public repositories.
11 | /// Note, that with Username/Password, you can make up to 5,000 requests per hour. 12 | /// For unauthenticated requests, the rate limit allows to make up to 60 requests per hour. 13 | /// Unauthenticated requests are associated with an IP address.
14 | /// Required, if you want to create webhooks 15 | Property Username As %String; 16 | 17 | /// GitHub password, corresponding to Username. Optional for public repositories. 18 | Property Password As %String; 19 | 20 | /// Namespace, where to download and compile repository 21 | Property Namespace As %String [ InitialExpression = {$Namespace} ]; 22 | 23 | /// Repository branch, usually master. Leave empty, if you want to receive default branch. 24 | Property Branch As %String [ InitialExpression = "master" ]; 25 | 26 | Method OnTask() As %Status 27 | { 28 | Return:'##class(%SYS.Namespace).Exists(..Namespace) $$$ERROR($$$NamespaceUnavailable,..Namespace) 29 | 30 | Set Owner = $p(..GitHubURL,"/",4) 31 | Set Repository = $p(..GitHubURL,"/",5) 32 | 33 | Return ..Update(Owner, Repository, ..Branch, ..Username, ..Password, ..Namespace) 34 | } 35 | 36 | /// Downloads and compiles GitHub repository.
37 | /// Owner - The name of the repository owner.
38 | /// Repository - The name of the repository.
39 | /// Branch - The name of the commit/branch/tag. If skipped the repository’s default branch (usually master) would be used.
40 | /// Username - GitHub user, who has access to repository. Optional for public repositories.
41 | /// Password - GitHub password, corresponding to Username. Optional for public repositories.
42 | /// Note, that with Username, you can make up to 5,000 requests per hour. 43 | /// For unauthenticated requests, the rate limit allows to make up to 60 requests per hour. 44 | /// Unauthenticated requests are associated with an IP address.
45 | /// Namespace - Namespace, where to download and compile repository.
46 | /// 47 | /// For example in the repository: https://github.com/intersystems-ru/Cache-MDX2JSON
48 | /// Owner - intersystems-ru, Repository - Cache-MDX2JSON.
49 | ClassMethod Update(Owner As %String, Repository As %String, Branch As %String = "", Username As %String = "", Password As %String = "", Namespace = {$Namespace}) As %Status 50 | { 51 | #dim req As %Net.HttpRequest 52 | Set req = ..CreateRequest(Username, Password) 53 | Set req.Location = "repos/" _ Owner _ "/" _ Repository _ "/contents" // as described in https://developer.github.com/v3/repos/ 54 | 55 | Set links = ##class(%ListOfDataTypes).%New() 56 | Set st = ..ProcessDirectory("",.req,Branch,.links) 57 | Return:$$$ISERR(st) st 58 | 59 | Set namespace = $Namespace 60 | Zn Namespace 61 | Set st = ..DownloadFiles(links,req,.list) 62 | zw list 63 | Set st2 = $system.OBJ.CompileList(.list,"cuk /checkuptodate=expandedonly") 64 | Zn namespace 65 | 66 | Return $$$ADDSC(st, st2) 67 | } 68 | 69 | /// Process one directory of GitHub repository. Recursive.
70 | /// Path -Internal repository path. Root is empty string
71 | /// Request - Authenticated/Set %Net.HttpRequest object.
72 | /// Links - List of links to raw files (which satisfy IsCacheFile conditions) from repository.
73 | ClassMethod ProcessDirectory(Path As %String = "", Request As %Net.HttpRequest, Branch As %String = "", ByRef Links As %ListOfDataTypes) As %Status 74 | { 75 | Set location = Request.Location 76 | Set Request.Location = Request.Location _ Path 77 | Do:(Branch'="") Request.SetParam("ref",Branch) 78 | 79 | Set st = Request.Get() 80 | 81 | Return:$$$ISERR(st) st 82 | Return:(Request.HttpResponse.StatusCode = 404) $$$ERROR($$$GeneralError,"Repository doesn't exist OR you don't have access") 83 | Return:((Request.HttpResponse.StatusCode = 403) && (Request.HttpResponse.GetHeader("X-RATELIMIT-REMAINING")=0)) $$$ERROR($$$GeneralError,"API rate limit exceeded. Try logging in.") 84 | Return:(Request.HttpResponse.StatusCode = 401) $$$ERROR($$$GeneralError,"We couldn't find that combination of username and password") 85 | Return:(Request.HttpResponse.StatusCode '= 200) $$$ERROR($$$GeneralError,"Received " _ Request.HttpResponse.StatusCode _ " expected 200") 86 | 87 | #dim objects As List of %ZEN.proxyObject 88 | #dim obj As %ZEN.proxyObject 89 | Set st = ##class(%ZEN.Auxiliary.jsonProvider).%ConvertJSONToObject(Request.HttpResponse.Data,,.objects,1) 90 | Return:$$$ISERR(st) st 91 | 92 | For i = 1:1:objects.Count() { 93 | Set obj = objects.GetAt(i) 94 | If (obj.type = "dir") { 95 | Set st = ..ProcessDirectory("/"_obj.name,Request,Branch,.Links) 96 | Return:$$$ISERR(st) st 97 | } ElseIf (obj.type = "file") { 98 | //Do:..IsCacheFile(obj) Links.Insert(obj."download_url") 99 | Do Links.Insert($LB(obj."download_url",..IsCacheFile(obj))) 100 | } Else { 101 | // obj.type = "symlink" or obj.type = "submodule" 102 | } 103 | } 104 | Set Request.Location = location // to keep track of where in the repository tree we are 105 | Return $$$OK 106 | } 107 | 108 | /// Check that incoming file is the one you need. 109 | ClassMethod IsCacheFile(File As %ZEN.proxyObject) As %Boolean 110 | { 111 | Set extensions = ",xml,cls,csp,csr,mac,int,bas,inc,gbl,prj,obj,pkg,gof,dfi,pivot,dashboard,html,css,js,ts,scss," 112 | Return:($L(File.name,".")=1) 0 //no extension 113 | Set File.Extension = $P(File.name,".",$L(File.name,".")) 114 | Return $F(extensions,","_$ZCVT(File.Extension,"l")_",") 115 | } 116 | 117 | /// Download list of files on https://raw.githubusercontent.com/ server.
118 | /// Links - List of links to raw files.
119 | /// Request - Authenticated/Set %Net.HttpRequest object.
120 | /// loadedlist - Returns an array of the items loaded. 121 | ClassMethod DownloadFiles(Links As %ListOfDataTypes, Request As %Net.HttpRequest, Output Items) As %Status 122 | { 123 | Kill Items 124 | Set Request.Server = "raw.githubusercontent.com" 125 | Set st = $$$OK 126 | Try 127 | { 128 | For i = 1:1:Links.Count() 129 | { 130 | Set link = $ListGet(Links.GetAt(i),1) 131 | Set bIsCacheFile = $ListGet(Links.GetAt(i),2) 132 | Set ^gitfiles(i,"link")=link 133 | Set ^gitfiles(i,"bIsCacheFile")=bIsCacheFile 134 | 135 | Set streq = Request.Get($e(link,35,*)) // Remove "https://raw.githubusercontent.com/" from URL. 136 | If $$$ISERR(streq) 137 | { 138 | Set st=$$$ADDSC(st, streq) 139 | Set ^gitfiles(i,"streq")=streq 140 | Continue 141 | } 142 | 143 | Set ^gitfiles(i,"stream")="starting..." 144 | Set binarystream = Request.HttpResponse.Data 145 | 146 | Do binarystream.Rewind() // just in case 147 | 148 | Set characterStream=##class(%GlobalCharacterStream).%New() //translating binary stream into character stream 149 | Set stTranslate=$$$OK 150 | Try 151 | { 152 | While 'binarystream.AtEnd 153 | { 154 | //Use eol to prevent breaking lines larger than 32Kb 155 | Set line=binarystream.ReadLine(, .stTranslate, .eol) 156 | Quit:$System.Status.IsError(stTranslate) 157 | 158 | If eol 159 | { 160 | Set stTranslate=characterStream.WriteLine(line) 161 | } 162 | Else 163 | { 164 | Set stTranslate=characterStream.Write(line) 165 | } 166 | Quit:$System.Status.IsError(stTranslate) 167 | } 168 | Quit:$System.Status.IsError(stTranslate) 169 | 170 | Do characterStream.Rewind() 171 | } 172 | Catch (oTranslateStreamException) 173 | { 174 | Set stTranslate=oTranslateStreamException.AsStatus() 175 | } 176 | 177 | If $System.Status.IsError(stTranslate) 178 | { 179 | //Could not convert binary stream to character stream 180 | //It is probably a binary file anyway 181 | Set characterStream="" 182 | Set st=$$$ADDSC(st, stTranslate) 183 | Set ^gitfiles(i,"stTranslate")=stTranslate 184 | } 185 | Set ^gitfiles(i,"stream")="Done" 186 | 187 | Do binarystream.Rewind() 188 | 189 | Set stload = $$$OK 190 | 191 | set items = "" 192 | If ('$IsObject(characterStream)) || (..IsUDLFile(characterStream)) 193 | { 194 | Set ^gitfiles(i,"IsUDLFile")="1" 195 | Set stload = ..LoadUDLFile(characterStream, binarystream, link, .items) 196 | } 197 | ElseIf bIsCacheFile 198 | { 199 | Set ^gitfiles(i,"IsUDLFile")="0" 200 | Set stload = $system.OBJ.LoadStream(characterStream,"",.error,.items,,,,"UTF8") 201 | } 202 | Set ^gitfiles(i,"stload")=stload 203 | If $$$ISERR(stload) 204 | { 205 | Set st=$$$ADDSC(st, stload) 206 | Continue 207 | } 208 | Merge Items = items // Does not overwrite existing array keys: Items(itemname)="" 209 | } 210 | 211 | Set Request.Server="api.github.com" 212 | } 213 | Catch (oException) 214 | { 215 | Set st = oException.AsStatus() 216 | If $D(i) Set ^gitfiles(i,"st final")=st 217 | } 218 | 219 | Quit st 220 | } 221 | 222 | ClassMethod CreateRequest(Username As %String, Password As %String) As %Net.HttpRequest 223 | { 224 | Set namespace = $Namespace 225 | Set SSLConfig = "GitHub" 226 | 227 | Zn "%SYS" 228 | Do:'##class(Security.SSLConfigs).Exists(SSLConfig) ##class(Security.SSLConfigs).Create(SSLConfig) 229 | Zn namespace 230 | 231 | Set req=##class(%Net.HttpRequest).%New() 232 | Set req.Https=1 233 | Set req.SSLConfiguration=SSLConfig 234 | Set req.Server="api.github.com" 235 | Do req.SetHeader("Accept","application/vnd.github.v3+json") // we want 3rd version of api 236 | 237 | If ($d(Username) && $d(Password) && (Username'="") && (Password'="")) { // supply Username and Password, if both are provided. GitHub accept Basic Auth 238 | Set req.Username = Username // https://developer.github.com/v3/auth/ 239 | Set req.Password = Password 240 | } 241 | 242 | Return req 243 | } 244 | 245 | } 246 | 247 | -------------------------------------------------------------------------------- /src/cls/CacheUpdater/UDL.cls: -------------------------------------------------------------------------------- 1 | Class CacheUpdater.UDL Extends %RegisteredObject 2 | { 3 | 4 | Parameter NamespacePar As %String = {$Namespace}; 5 | 6 | /// Checks whether this file is in UDL format 7 | /// stream - stream which contains file definition 8 | ClassMethod IsUDLFile(stream As %GlobalCharacterStream) As %Boolean 9 | { 10 | // probably 10 lines is enough 11 | set counter = 0 12 | while 'stream.AtEnd { 13 | if counter >= 10 { 14 | quit 15 | } 16 | set line = stream.ReadLine() 17 | if $find(line, "line - any string.
30 | ClassMethod ReadName(line As %String) As %String 31 | { 32 | set trimmed = $zstrip(line, "<>W") 33 | return $piece(trimmed, " ") 34 | } 35 | 36 | /// Finds a name of a class 37 | /// stream - stream which contains a class definition
38 | /// name - name which contains the name of class
39 | ClassMethod GetClassName(stream As %GlobalCharacterStream, ByRef name As %String) As %Status 40 | { 41 | while 'stream.AtEnd { 42 | set line = stream.ReadLine() 43 | 44 | if $extract(line, 1, 3) = "///" { // check for inline comments 45 | continue 46 | } elseif $zconvert($extract(line, 1, 5), "l") = "class" { 47 | set line = $extract(line, 6, *) 48 | set name = ..ReadName(line) 49 | if name = "" { 50 | return '$$$OK 51 | } else { 52 | return $$$OK 53 | } 54 | } 55 | } 56 | return '$$$OK 57 | } 58 | 59 | /// Finds a name of a routine 60 | /// stream - stream which contains a routine definition
61 | /// name - name which contains the name of routine
62 | /// type - type of file {1 - mac, 2 - inc, 3 - int} 63 | ClassMethod GetRoutineName(stream As %GlobalCharacterStream, ByRef name As %String, ByRef type As %Integer) As %Status 64 | { 65 | while 'stream.AtEnd { 66 | set line = stream.ReadLine() 67 | set index = $find(line, "ROUTINE") 68 | // TODO - check whether the name on the next line 69 | // or something is between ROUTINE and name 70 | if index { 71 | if $find(line, "[Type=INC]") { 72 | set type = 2 73 | } 74 | elseif $find(line, "[Type=INT,Generated]") { 75 | set type = 3 76 | } 77 | else { 78 | set type = 1 79 | } 80 | set line = $extract(line, index, *) 81 | set name = ..ReadName(line) 82 | if name = "" { 83 | return '$$$OK 84 | } else { 85 | return $$$OK 86 | } 87 | } 88 | } 89 | return '$$$OK 90 | } 91 | 92 | /// Finds a name of a dfi 93 | /// stream - stream which contains a dfi definition
94 | /// name - name which contains the name of dfi
95 | ClassMethod GetDFIName(stream As %GlobalCharacterStream, ByRef name As %String) As %Status 96 | { 97 | #dim textreader As %XML.TextReader 98 | set dfiContent = "" 99 | 100 | // I don't know why but if i just parse stream it doesn't work 101 | while 'stream.AtEnd { 102 | set dfiContent = dfiContent _ stream.Read() 103 | } 104 | 105 | set st = ##class(%XML.TextReader).ParseString(dfiContent, .textreader) 106 | return:$$$ISERR(st) st 107 | 108 | while textreader.Read() { 109 | set node = textreader.Name 110 | if (node = "pivot") || (node = "dashboard") { 111 | do textreader.MoveToAttributeName("folderName") 112 | // set dfiFolderName = $translate(textreader.Value, " ", "-") 113 | set dfiFolderName=textreader.Value 114 | 115 | do textreader.MoveToAttributeName("name") 116 | // set dfiName = $translate(textreader.Value, " ", "-") 117 | set dfiName=textreader.Value 118 | set name = dfiFolderName _ "-" _ dfiName _ "." _ node _ ".dfi" 119 | return $$$OK 120 | } 121 | } 122 | return '$$$OK 123 | } 124 | 125 | /// Get extension of the file by url 126 | /// url - the url where the file is located in the web.
127 | ClassMethod GetExt(url As %String) As %String 128 | { 129 | //return $zconvert($piece(url, ".", *), "l") 130 | //AMIR: There are parameters after the extension that are not part of the extension 131 | return $zconvert($piece($piece(url, ".", *),"?"), "l") 132 | } 133 | 134 | /// Check whether a file is a web file 135 | /// ext - extensions of the file
136 | ClassMethod IsWebFile(ext As %String) As %String 137 | { 138 | set webExts = "csp,html,css,js,ts,scss" 139 | return $find(webExts, ext) 140 | } 141 | 142 | /// Imports the file in UDL file in the project 143 | /// contentStream - the stream which contains the source code in udl format.
144 | /// url - the url where the file is located in the web.
145 | /// list - array of files to compile
146 | ClassMethod LoadUDLFile(contentStream As %GlobalCharacterStream, binaryStream As %Stream.FileCharacterGzip, url As %String, list As %String) As %Status 147 | { 148 | set st = $$$OK 149 | 150 | set ext = ..GetExt(url) 151 | 152 | if ext = "cls" { 153 | set st = ..CreateClass(contentStream, url, .list) 154 | } 155 | elseif ext = "dfi" { 156 | set st = ..CreateDFI(contentStream, url, .list) 157 | } 158 | elseif (ext = "inc") || (ext = "mac") { 159 | set st = ..CreateRoutine(contentStream, url, .list) 160 | } 161 | else 162 | { 163 | set st = ..CreateWebFile(contentStream, binaryStream, url, ext, .list) 164 | } 165 | return st 166 | } 167 | 168 | /// Checks whether the class exists 169 | /// className - name of the class.
170 | ClassMethod DoesClassExist(className As %String) As %Boolean 171 | { 172 | Set query = "SELECT TOP 1 COUNT(ID) FROM %Dictionary.ClassDefinition WHERE ID = ?" 173 | Set statement = ##class(%SQL.Statement).%New() 174 | Set st = statement.%Prepare(query) 175 | Set rset = statement.%Execute(className) 176 | If (rset.%Next()) && (rset.%ROWCOUNT > 0) { 177 | Return $$$YES 178 | } 179 | Return $$$NO 180 | } 181 | 182 | /// Creates and imports the class into the project from stream 183 | /// contentStream - the stream which contains the source code in udl format.
184 | /// url - the url where the file is located in the web.
185 | /// list - array of files to compile
186 | ClassMethod CreateClass(contentStream As %CharacterStream, url As %String, ByRef list As %String) As %Status 187 | { 188 | Set st = ..GetClassName(contentStream, .className) 189 | Return:$$$ISERR(st) st 190 | 191 | set list(className _ ".cls") = "" 192 | 193 | Do contentStream.Rewind() 194 | 195 | if '(##class(%Dictionary.ClassDefinition).%ExistsId(className)) { 196 | Set clsDef = ##class(%Dictionary.ClassDefinition).%New() 197 | Set clsDef.Name = className 198 | Set st = clsDef.%Save() 199 | Return:$$$ISERR(st) st 200 | } 201 | 202 | 203 | Set namespace = $namespace 204 | Set $namespace = ..#NamespacePar 205 | Set st = ##class(CacheUpdater.TextServices).SetTextFromStream(namespace,className, contentStream) 206 | Set $namespace = namespace 207 | 208 | if st { 209 | w !, "Imported " _ className, ! 210 | } 211 | 212 | Return st 213 | } 214 | 215 | /// Creates and imports the dfi file into the project from stream 216 | /// contentStream - the stream which contains the source code in udl format.
217 | /// list - array of files to compile
218 | ClassMethod CreateDFI(contentStream As %CharacterStream, url As %String, ByRef list As %String) As %Status 219 | { 220 | Set st = $$$OK 221 | Try { 222 | Set st = ..GetDFIName(contentStream, .name) 223 | Return:$$$ISERR(st) st 224 | 225 | set list(name) = "" 226 | 227 | Set tDoc = ##class(%DeepSee.UI.FolderItemDocument).%New(name) 228 | Set st = tDoc.ImportFromXML(contentStream) 229 | Return:$$$ISERR(st) st 230 | 231 | Set st = tDoc.Save() 232 | if st { 233 | w !, "Imported " _ name, ! 234 | } 235 | Return:$$$ISERR(st) st 236 | } Catch e { 237 | Set st = e.AsStatus() 238 | } 239 | Return st 240 | } 241 | 242 | /// Creates and imports mac, int, inc files into the project from stream 243 | /// contentStream - the stream which contains the source code in udl format.
244 | /// url - the url where the file is located in the web.
245 | /// list - array of files to compile
246 | ClassMethod CreateRoutine(contentStream As %GlobalCharacterStream, url As %String, ByRef list As %String) As %Status 247 | { 248 | Set st = ..GetRoutineName(contentStream, .name, .type) 249 | do contentStream.Rewind() 250 | 251 | return:$$$ISERR(st) st 252 | 253 | if type = 1 { 254 | set name = name _ ".mac" 255 | } 256 | elseif type = 2 { 257 | set name = name _ ".inc" 258 | } 259 | elseif type = 3 { 260 | set name = name _ ".int" 261 | } 262 | 263 | set list(name) = "" 264 | 265 | Set rtn = ##class(%Routine).%New(name) 266 | While 'contentStream.AtEnd { 267 | Set line = contentStream.ReadLine() 268 | If $Find(line, "ROUTINE") { 269 | Continue 270 | } 271 | Do rtn.WriteLine(line) 272 | } 273 | 274 | Set st = rtn.Save() 275 | Return:$$$ISERR(st) st 276 | 277 | if st { 278 | w !, "Imported " _ name, ! 279 | } 280 | Return st 281 | } 282 | 283 | /// Creates and imports mac, int, inc files into the project from stream 284 | /// contentStream - the stream which contains the source code in udl format.
285 | /// url - the url where the file is located in the web.
286 | /// ext - extension of the file
287 | /// list - array of files to compile
288 | ClassMethod CreateWebFile(contentStream As %GlobalCharacterStream, binaryStream As %Stream.FileCharacterGzip, url As %String, ext As %String, ByRef list As %String) As %Status 289 | { 290 | Set st = $$$OK 291 | Try 292 | { 293 | Set tCSPRootPath = $system.CSP.GetFileName($system.CSP.GetDefaultApp($namespace)_"/") 294 | 295 | Set tFileName = $Piece($Piece(url,"?",1),"/",*) 296 | Set tCSPSubPath = $Piece(url,"/",7,*-1)_"/" 297 | 298 | set tFileDirectory = tCSPRootPath_tCSPSubPath 299 | Set tFullFileName = tFileDirectory_tFileName 300 | 301 | //On Windows, tFullFileName will contain \ and / but CreateDirectoryChain() and 302 | //LinkToFile() already normalize the paths accordingly to the OS for us so 303 | //we don't have to worry about it. 304 | If '##class(%File).CreateDirectoryChain(tFileDirectory) 305 | { 306 | Set st = $System.Status.Error(5001,"Could nor create path chain '"_tFileDirectory_"'") 307 | Quit 308 | } 309 | 310 | Set filestream = ##class(%Stream.FileCharacter).%New() 311 | set st = filestream.LinkToFile(tFullFileName) 312 | Quit:$System.Status.IsError(st) 313 | 314 | If $IsObject(contentStream) && ..IsWebFile(ext) 315 | { 316 | Set st=filestream.CopyFrom(contentStream) 317 | } 318 | Else 319 | { 320 | Set st=filestream.CopyFrom(binaryStream) 321 | } 322 | Quit:$System.Status.IsError(st) 323 | 324 | set st = filestream.%Save() 325 | Quit:$System.Status.IsError(st) 326 | 327 | Write !, "Imported " _ tFullFileName, ! 328 | } 329 | Catch (oException) 330 | { 331 | Set st = oException.AsStatus() 332 | } 333 | 334 | Quit st 335 | } 336 | 337 | } 338 | 339 | --------------------------------------------------------------------------------