├── 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 |
--------------------------------------------------------------------------------