1
0

AmberCli.st 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. Smalltalk current createPackage: 'AmberCli'!
  2. Object subclass: #AmberCli
  3. instanceVariableNames: ''
  4. package: 'AmberCli'!
  5. !AmberCli commentStamp!
  6. I am the Amber CLI (CommandLine Interface) tool which runs on Node.js.
  7. My responsibility is to start different Amber programs like the FileServer or the Repl.
  8. Which program to start is determined by the first commandline parameters passed to the AmberCli executable.
  9. Use `help` to get a list of all available options.
  10. Any further commandline parameters are passed to the specific program.
  11. ## Commands
  12. New commands can be added by creating a unary class side method in the `commands` protocol.
  13. Any `camelCaseCommand` is transformed into a commandline parameter of the form `camel-case-command` and vice versa.!
  14. !AmberCli class methodsFor: 'commandline'!
  15. commandLineSwitches
  16. "Collect all methodnames from the 'commands' protocol of the class
  17. and select the ones with only one parameter.
  18. Then remove the ':' at the end of the name.
  19. Additionally all uppercase letters are made lowercase and preceded by a '-'.
  20. Example: fallbackPage: becomes --fallback-page.
  21. Return the Array containing the commandline switches."
  22. | switches |
  23. switches := ((self class methodsInProtocol: 'commands') collect: [ :each | each selector]).
  24. switches := switches select: [ :each | each match: '^[^:]*:$'].
  25. switches :=switches collect: [ :each |
  26. (each allButLast replace: '([A-Z])' with: '-$1') asLowercase].
  27. ^switches
  28. !
  29. handleArguments: args
  30. | command |
  31. command := self selectorForCommandLineSwitch: (args first).
  32. args remove: args first.
  33. self perform: command withArguments: (Array with: args).
  34. !
  35. selectorForCommandLineSwitch: aSwitch
  36. "Add ':' at the end
  37. and replace all occurences of a lowercase letter preceded by a '-' with
  38. the Uppercase letter.
  39. Example: fallback-page becomes fallbackPage:"
  40. ^(aSwitch replace: '-[a-z]' with: [ :each | each second asUppercase ]), ':'
  41. ! !
  42. !AmberCli class methodsFor: 'commands'!
  43. help: args
  44. console log: 'Available Commands:'.
  45. self commandLineSwitches do: [ :each | console log: each ]
  46. !
  47. repl: args
  48. ^Repl new createInterface
  49. !
  50. serve: args
  51. ^(FileServer createServerWithArguments: args) start
  52. ! !
  53. !AmberCli class methodsFor: 'startup'!
  54. main
  55. "Main entry point for Amber applications.
  56. Parses commandline arguments and starts the according subprogram."
  57. | args |
  58. args := process argv.
  59. "Remove the first args which contain the path to the node executable and the script file."
  60. args removeFrom: 1 to: 3.
  61. (args isEmpty)
  62. ifTrue: [self help: nil]
  63. ifFalse: [^self handleArguments: args]
  64. ! !
  65. Object subclass: #FileServer
  66. instanceVariableNames: 'path http fs url host port basePath util username password fallbackPage'
  67. package: 'AmberCli'!
  68. !FileServer commentStamp!
  69. I am the Amber Smalltalk FileServer.
  70. My runtime requirement is a functional Node.js executable.
  71. To start a FileServer instance on port `4000` use the following code:
  72. FileServer new start
  73. A parameterized instance can be created with the following code:
  74. FileServer createServerWithArguments: options
  75. Here, `options` is an array of commandline style strings each followed by a value e.g. `#('--port', '6000', '--host', '0.0.0.0')`.
  76. A list of all available parameters can be printed to the commandline by passing `--help` as parameter.
  77. See the `Options` section for further details on how options are mapped to instance methods.
  78. After startup FileServer checks if the directory layout required by Amber is present and logs a warning on absence.
  79. ## Options
  80. Each option is of the form `--some-option-string` which is transformed into a selector of the format `someOptionString:`.
  81. The trailing `--` gets removed, each `-[a-z]` gets transformed into the according uppercase letter, and a `:` is appended to create a selector which takes a single argument.
  82. Afterwards, the selector gets executed on the `FileServer` instance with the value following in the options array as parameter.
  83. ## Adding new commandline parameters
  84. Adding new commandline parameters to `FileServer` is as easy as adding a new single parameter method to the `accessing` protocol.!
  85. !FileServer methodsFor: 'accessing'!
  86. basePath
  87. ^basePath ifNil: ['./']
  88. !
  89. basePath: aString
  90. basePath := aString
  91. !
  92. fallbackPage
  93. ^fallbackPage
  94. !
  95. fallbackPage: aString
  96. fallbackPage := aString
  97. !
  98. host
  99. ^host
  100. !
  101. host: hostname
  102. host := hostname
  103. !
  104. password: aPassword
  105. password := aPassword.
  106. !
  107. port
  108. ^port
  109. !
  110. port: aNumber
  111. port := aNumber
  112. !
  113. username: aUsername
  114. username := aUsername.
  115. ! !
  116. !FileServer methodsFor: 'initialization'!
  117. checkDirectoryLayout
  118. (fs existsSync: self basePath, 'index.html') ifFalse: [
  119. console warn: 'Warning: project directory does not contain index.html'].
  120. (fs existsSync: self basePath, 'st') ifFalse: [
  121. console warn: 'Warning: project directory is missing an "st" directory'].
  122. (fs existsSync: self basePath, 'js') ifFalse: [
  123. console warn: 'Warning: project directory is missing a "js" directory'].
  124. !
  125. initialize
  126. super initialize.
  127. path := self require: 'path'.
  128. http := self require: 'http'.
  129. fs := self require: 'fs'.
  130. util := self require: 'util'.
  131. url := self require: 'url'.
  132. host := self class defaultHost.
  133. port := self class defaultPort.
  134. username := nil.
  135. password := nil.
  136. fallbackPage := nil.
  137. ! !
  138. !FileServer methodsFor: 'private'!
  139. base64Decode: aString
  140. <return (new Buffer(aString, 'base64').toString())>
  141. !
  142. isAuthenticated: aRequest
  143. "Basic HTTP Auth: http://stackoverflow.com/a/5957629/293175
  144. and https://gist.github.com/1686663"
  145. | header token auth parts|
  146. (username isNil and: [password isNil]) ifTrue: [^true].
  147. "get authentication header"
  148. header := (aRequest headers at: 'authorization') ifNil:[''].
  149. (header isEmpty)
  150. ifTrue: [^false]
  151. ifFalse: [
  152. "get authentication token"
  153. token := (header tokenize: ' ') ifNil:[''].
  154. "convert back from base64"
  155. auth := self base64Decode: (token at: 2).
  156. "split token at colon"
  157. parts := auth tokenize: ':'.
  158. ((username = (parts at: 1)) and: [password = (parts at: 2)])
  159. ifTrue: [^true]
  160. ifFalse: [^false]
  161. ].
  162. !
  163. require: aModuleString
  164. "call to the require function"
  165. ^require value: aModuleString
  166. !
  167. writeData: data toFileNamed: aFilename
  168. console log: aFilename
  169. ! !
  170. !FileServer methodsFor: 'request handling'!
  171. handleGETRequest: aRequest respondTo: aResponse
  172. | uri filename |
  173. uri := (url parse: aRequest url) pathname.
  174. filename := path join: self basePath with: uri.
  175. fs exists: filename do: [:aBoolean |
  176. aBoolean
  177. ifFalse: [self respondNotFoundTo: aResponse]
  178. ifTrue: [self respondFileNamed: filename to: aResponse]]
  179. !
  180. handleOPTIONSRequest: aRequest respondTo: aResponse
  181. aResponse writeHead: 200 options: #{'Access-Control-Allow-Origin' -> '*'.
  182. 'Access-Control-Allow-Methods' -> 'GET, PUT, POST, DELETE, OPTIONS'.
  183. 'Access-Control-Allow-Headers' -> 'Content-Type, Accept'.
  184. 'Content-Length' -> 0.
  185. 'Access-Control-Max-Age' -> 10}.
  186. aResponse end
  187. !
  188. handlePUTRequest: aRequest respondTo: aResponse
  189. | file stream |
  190. (self isAuthenticated: aRequest)
  191. ifFalse: [self respondAuthenticationRequiredTo: aResponse. ^nil].
  192. file := '.', aRequest url.
  193. stream := fs createWriteStream: file.
  194. stream on: 'error' do: [:error |
  195. console warn: 'Error creating WriteStream for file ', file.
  196. console warn: ' Did you forget to create the necessary js/ or st/ directory in your project?'.
  197. console warn: ' The exact error is: ', error.
  198. self respondNotCreatedTo: aResponse].
  199. stream on: 'close' do: [
  200. self respondCreatedTo: aResponse].
  201. aRequest setEncoding: 'utf8'.
  202. aRequest on: 'data' do: [:data |
  203. stream write: data].
  204. aRequest on: 'end' do: [
  205. stream writable ifTrue: [stream end]]
  206. !
  207. handleRequest: aRequest respondTo: aResponse
  208. aRequest method = 'PUT'
  209. ifTrue: [self handlePUTRequest: aRequest respondTo: aResponse].
  210. aRequest method = 'GET'
  211. ifTrue:[self handleGETRequest: aRequest respondTo: aResponse].
  212. aRequest method = 'OPTIONS'
  213. ifTrue:[self handleOPTIONSRequest: aRequest respondTo: aResponse]
  214. !
  215. respondAuthenticationRequiredTo: aResponse
  216. aResponse
  217. writeHead: 401 options: #{'WWW-Authenticate' -> 'Basic realm="Secured Developer Area"'};
  218. write: '<html><body>Authentication needed</body></html>';
  219. end.
  220. !
  221. respondCreatedTo: aResponse
  222. aResponse
  223. writeHead: 201 options: #{'Content-Type' -> 'text/plain'. 'Access-Control-Allow-Origin' -> '*'};
  224. end.
  225. !
  226. respondFileNamed: aFilename to: aResponse
  227. | type filename |
  228. filename := aFilename.
  229. (fs statSync: aFilename) isDirectory ifTrue: [
  230. filename := filename, 'index.html'].
  231. fs readFile: filename do: [:ex :file |
  232. ex notNil
  233. ifTrue: [
  234. console log: filename, ' does not exist'.
  235. self respondInternalErrorTo: aResponse]
  236. ifFalse: [
  237. type := self class mimeTypeFor: filename.
  238. type = 'application/javascript'
  239. ifTrue: [ type:=type,';charset=utf-8' ].
  240. aResponse
  241. writeHead: 200 options: #{'Content-Type' -> type};
  242. write: file encoding: 'binary';
  243. end]]
  244. !
  245. respondInternalErrorTo: aResponse
  246. aResponse
  247. writeHead: 500 options: #{'Content-Type' -> 'text/plain'};
  248. write: '500 Internal server error';
  249. end
  250. !
  251. respondNotCreatedTo: aResponse
  252. aResponse
  253. writeHead: 400 options: #{'Content-Type' -> 'text/plain'};
  254. write: 'File could not be created. Did you forget to create the st/js directories on the server?';
  255. end.
  256. !
  257. respondNotFoundTo: aResponse
  258. self fallbackPage isNil ifFalse: [^self respondFileNamed: self fallbackPage to: aResponse].
  259. aResponse
  260. writeHead: 404 options: #{'Content-Type' -> 'text/plain'};
  261. write: '404 Not found';
  262. end
  263. !
  264. respondOKTo: aResponse
  265. aResponse
  266. writeHead: 200 options: #{'Content-Type' -> 'text/plain'. 'Access-Control-Allow-Origin' -> '*'};
  267. end.
  268. ! !
  269. !FileServer methodsFor: 'starting'!
  270. start
  271. "Checks if required directory layout is present (issue warning if not).
  272. Afterwards start the server."
  273. self checkDirectoryLayout.
  274. (http createServer: [:request :response |
  275. self handleRequest: request respondTo: response])
  276. on: 'error' do: [:error | console log: 'Error starting server: ', error];
  277. on: 'listening' do: [console log: 'Starting file server on ', self host, ':', self port asString];
  278. listen: self port host: self host.
  279. !
  280. startOn: aPort
  281. self port: aPort.
  282. self start
  283. ! !
  284. FileServer class instanceVariableNames: 'mimeTypes'!
  285. !FileServer class methodsFor: 'accessing'!
  286. commandLineSwitches
  287. "Collect all methodnames from the 'accessing' protocol
  288. and select the ones with only one parameter.
  289. Then remove the ':' at the end of the name
  290. and add a '--' at the beginning.
  291. Additionally all uppercase letters are made lowercase and preceded by a '-'.
  292. Example: fallbackPage: becomes --fallback-page.
  293. Return the Array containing the commandline switches."
  294. | switches |
  295. switches := ((self methodsInProtocol: 'accessing') collect: [ :each | each selector]).
  296. switches := switches select: [ :each | each match: '^[^:]*:$'].
  297. switches :=switches collect: [ :each |
  298. (each allButLast replace: '([A-Z])' with: '-$1') asLowercase replace: '^([a-z])' with: '--$1' ].
  299. ^switches
  300. !
  301. defaultHost
  302. ^'127.0.0.1'
  303. !
  304. defaultMimeTypes
  305. ^ #{
  306. '%' -> 'application/x-trash'.
  307. '323' -> 'text/h323'.
  308. 'abw' -> 'application/x-abiword'.
  309. 'ai' -> 'application/postscript'.
  310. 'aif' -> 'audio/x-aiff'.
  311. 'aifc' -> 'audio/x-aiff'.
  312. 'aiff' -> 'audio/x-aiff'.
  313. 'alc' -> 'chemical/x-alchemy'.
  314. 'art' -> 'image/x-jg'.
  315. 'asc' -> 'text/plain'.
  316. 'asf' -> 'video/x-ms-asf'.
  317. 'asn' -> 'chemical/x-ncbi-asn1-spec'.
  318. 'aso' -> 'chemical/x-ncbi-asn1-binary'.
  319. 'asx' -> 'video/x-ms-asf'.
  320. 'au' -> 'audio/basic'.
  321. 'avi' -> 'video/x-msvideo'.
  322. 'b' -> 'chemical/x-molconn-Z'.
  323. 'bak' -> 'application/x-trash'.
  324. 'bat' -> 'application/x-msdos-program'.
  325. 'bcpio' -> 'application/x-bcpio'.
  326. 'bib' -> 'text/x-bibtex'.
  327. 'bin' -> 'application/octet-stream'.
  328. 'bmp' -> 'image/x-ms-bmp'.
  329. 'book' -> 'application/x-maker'.
  330. 'bsd' -> 'chemical/x-crossfire'.
  331. 'c' -> 'text/x-csrc'.
  332. 'c++' -> 'text/x-c++src'.
  333. 'c3d' -> 'chemical/x-chem3d'.
  334. 'cac' -> 'chemical/x-cache'.
  335. 'cache' -> 'chemical/x-cache'.
  336. 'cascii' -> 'chemical/x-cactvs-binary'.
  337. 'cat' -> 'application/vnd.ms-pki.seccat'.
  338. 'cbin' -> 'chemical/x-cactvs-binary'.
  339. 'cc' -> 'text/x-c++src'.
  340. 'cdf' -> 'application/x-cdf'.
  341. 'cdr' -> 'image/x-coreldraw'.
  342. 'cdt' -> 'image/x-coreldrawtemplate'.
  343. 'cdx' -> 'chemical/x-cdx'.
  344. 'cdy' -> 'application/vnd.cinderella'.
  345. 'cef' -> 'chemical/x-cxf'.
  346. 'cer' -> 'chemical/x-cerius'.
  347. 'chm' -> 'chemical/x-chemdraw'.
  348. 'chrt' -> 'application/x-kchart'.
  349. 'cif' -> 'chemical/x-cif'.
  350. 'class' -> 'application/java-vm'.
  351. 'cls' -> 'text/x-tex'.
  352. 'cmdf' -> 'chemical/x-cmdf'.
  353. 'cml' -> 'chemical/x-cml'.
  354. 'cod' -> 'application/vnd.rim.cod'.
  355. 'com' -> 'application/x-msdos-program'.
  356. 'cpa' -> 'chemical/x-compass'.
  357. 'cpio' -> 'application/x-cpio'.
  358. 'cpp' -> 'text/x-c++src'.
  359. 'cpt' -> 'image/x-corelphotopaint'.
  360. 'crl' -> 'application/x-pkcs7-crl'.
  361. 'crt' -> 'application/x-x509-ca-cert'.
  362. 'csf' -> 'chemical/x-cache-csf'.
  363. 'csh' -> 'text/x-csh'.
  364. 'csm' -> 'chemical/x-csml'.
  365. 'csml' -> 'chemical/x-csml'.
  366. 'css' -> 'text/css'.
  367. 'csv' -> 'text/comma-separated-values'.
  368. 'ctab' -> 'chemical/x-cactvs-binary'.
  369. 'ctx' -> 'chemical/x-ctx'.
  370. 'cu' -> 'application/cu-seeme'.
  371. 'cub' -> 'chemical/x-gaussian-cube'.
  372. 'cxf' -> 'chemical/x-cxf'.
  373. 'cxx' -> 'text/x-c++src'.
  374. 'dat' -> 'chemical/x-mopac-input'.
  375. 'dcr' -> 'application/x-director'.
  376. 'deb' -> 'application/x-debian-package'.
  377. 'dif' -> 'video/dv'.
  378. 'diff' -> 'text/plain'.
  379. 'dir' -> 'application/x-director'.
  380. 'djv' -> 'image/vnd.djvu'.
  381. 'djvu' -> 'image/vnd.djvu'.
  382. 'dl' -> 'video/dl'.
  383. 'dll' -> 'application/x-msdos-program'.
  384. 'dmg' -> 'application/x-apple-diskimage'.
  385. 'dms' -> 'application/x-dms'.
  386. 'doc' -> 'application/msword'.
  387. 'dot' -> 'application/msword'.
  388. 'dv' -> 'video/dv'.
  389. 'dvi' -> 'application/x-dvi'.
  390. 'dx' -> 'chemical/x-jcamp-dx'.
  391. 'dxr' -> 'application/x-director'.
  392. 'emb' -> 'chemical/x-embl-dl-nucleotide'.
  393. 'embl' -> 'chemical/x-embl-dl-nucleotide'.
  394. 'ent' -> 'chemical/x-pdb'.
  395. 'eps' -> 'application/postscript'.
  396. 'etx' -> 'text/x-setext'.
  397. 'exe' -> 'application/x-msdos-program'.
  398. 'ez' -> 'application/andrew-inset'.
  399. 'fb' -> 'application/x-maker'.
  400. 'fbdoc' -> 'application/x-maker'.
  401. 'fch' -> 'chemical/x-gaussian-checkpoint'.
  402. 'fchk' -> 'chemical/x-gaussian-checkpoint'.
  403. 'fig' -> 'application/x-xfig'.
  404. 'flac' -> 'application/x-flac'.
  405. 'fli' -> 'video/fli'.
  406. 'fm' -> 'application/x-maker'.
  407. 'frame' -> 'application/x-maker'.
  408. 'frm' -> 'application/x-maker'.
  409. 'gal' -> 'chemical/x-gaussian-log'.
  410. 'gam' -> 'chemical/x-gamess-input'.
  411. 'gamin' -> 'chemical/x-gamess-input'.
  412. 'gau' -> 'chemical/x-gaussian-input'.
  413. 'gcd' -> 'text/x-pcs-gcd'.
  414. 'gcf' -> 'application/x-graphing-calculator'.
  415. 'gcg' -> 'chemical/x-gcg8-sequence'.
  416. 'gen' -> 'chemical/x-genbank'.
  417. 'gf' -> 'application/x-tex-gf'.
  418. 'gif' -> 'image/gif'.
  419. 'gjc' -> 'chemical/x-gaussian-input'.
  420. 'gjf' -> 'chemical/x-gaussian-input'.
  421. 'gl' -> 'video/gl'.
  422. 'gnumeric' -> 'application/x-gnumeric'.
  423. 'gpt' -> 'chemical/x-mopac-graph'.
  424. 'gsf' -> 'application/x-font'.
  425. 'gsm' -> 'audio/x-gsm'.
  426. 'gtar' -> 'application/x-gtar'.
  427. 'h' -> 'text/x-chdr'.
  428. 'h++' -> 'text/x-c++hdr'.
  429. 'hdf' -> 'application/x-hdf'.
  430. 'hh' -> 'text/x-c++hdr'.
  431. 'hin' -> 'chemical/x-hin'.
  432. 'hpp' -> 'text/x-c++hdr'.
  433. 'hqx' -> 'application/mac-binhex40'.
  434. 'hs' -> 'text/x-haskell'.
  435. 'hta' -> 'application/hta'.
  436. 'htc' -> 'text/x-component'.
  437. 'htm' -> 'text/html'.
  438. 'html' -> 'text/html'.
  439. 'hxx' -> 'text/x-c++hdr'.
  440. 'ica' -> 'application/x-ica'.
  441. 'ice' -> 'x-conference/x-cooltalk'.
  442. 'ico' -> 'image/x-icon'.
  443. 'ics' -> 'text/calendar'.
  444. 'icz' -> 'text/calendar'.
  445. 'ief' -> 'image/ief'.
  446. 'iges' -> 'model/iges'.
  447. 'igs' -> 'model/iges'.
  448. 'iii' -> 'application/x-iphone'.
  449. 'inp' -> 'chemical/x-gamess-input'.
  450. 'ins' -> 'application/x-internet-signup'.
  451. 'iso' -> 'application/x-iso9660-image'.
  452. 'isp' -> 'application/x-internet-signup'.
  453. 'ist' -> 'chemical/x-isostar'.
  454. 'istr' -> 'chemical/x-isostar'.
  455. 'jad' -> 'text/vnd.sun.j2me.app-descriptor'.
  456. 'jar' -> 'application/java-archive'.
  457. 'java' -> 'text/x-java'.
  458. 'jdx' -> 'chemical/x-jcamp-dx'.
  459. 'jmz' -> 'application/x-jmol'.
  460. 'jng' -> 'image/x-jng'.
  461. 'jnlp' -> 'application/x-java-jnlp-file'.
  462. 'jpe' -> 'image/jpeg'.
  463. 'jpeg' -> 'image/jpeg'.
  464. 'jpg' -> 'image/jpeg'.
  465. 'js' -> 'application/javascript'.
  466. 'kar' -> 'audio/midi'.
  467. 'key' -> 'application/pgp-keys'.
  468. 'kil' -> 'application/x-killustrator'.
  469. 'kin' -> 'chemical/x-kinemage'.
  470. 'kpr' -> 'application/x-kpresenter'.
  471. 'kpt' -> 'application/x-kpresenter'.
  472. 'ksp' -> 'application/x-kspread'.
  473. 'kwd' -> 'application/x-kword'.
  474. 'kwt' -> 'application/x-kword'.
  475. 'latex' -> 'application/x-latex'.
  476. 'lha' -> 'application/x-lha'.
  477. 'lhs' -> 'text/x-literate-haskell'.
  478. 'lsf' -> 'video/x-la-asf'.
  479. 'lsx' -> 'video/x-la-asf'.
  480. 'ltx' -> 'text/x-tex'.
  481. 'lzh' -> 'application/x-lzh'.
  482. 'lzx' -> 'application/x-lzx'.
  483. 'm3u' -> 'audio/x-mpegurl'.
  484. 'm4a' -> 'audio/mpeg'.
  485. 'maker' -> 'application/x-maker'.
  486. 'man' -> 'application/x-troff-man'.
  487. 'mcif' -> 'chemical/x-mmcif'.
  488. 'mcm' -> 'chemical/x-macmolecule'.
  489. 'mdb' -> 'application/msaccess'.
  490. 'me' -> 'application/x-troff-me'.
  491. 'mesh' -> 'model/mesh'.
  492. 'mid' -> 'audio/midi'.
  493. 'midi' -> 'audio/midi'.
  494. 'mif' -> 'application/x-mif'.
  495. 'mm' -> 'application/x-freemind'.
  496. 'mmd' -> 'chemical/x-macromodel-input'.
  497. 'mmf' -> 'application/vnd.smaf'.
  498. 'mml' -> 'text/mathml'.
  499. 'mmod' -> 'chemical/x-macromodel-input'.
  500. 'mng' -> 'video/x-mng'.
  501. 'moc' -> 'text/x-moc'.
  502. 'mol' -> 'chemical/x-mdl-molfile'.
  503. 'mol2' -> 'chemical/x-mol2'.
  504. 'moo' -> 'chemical/x-mopac-out'.
  505. 'mop' -> 'chemical/x-mopac-input'.
  506. 'mopcrt' -> 'chemical/x-mopac-input'.
  507. 'mov' -> 'video/quicktime'.
  508. 'movie' -> 'video/x-sgi-movie'.
  509. 'mp2' -> 'audio/mpeg'.
  510. 'mp3' -> 'audio/mpeg'.
  511. 'mp4' -> 'video/mp4'.
  512. 'mpc' -> 'chemical/x-mopac-input'.
  513. 'mpe' -> 'video/mpeg'.
  514. 'mpeg' -> 'video/mpeg'.
  515. 'mpega' -> 'audio/mpeg'.
  516. 'mpg' -> 'video/mpeg'.
  517. 'mpga' -> 'audio/mpeg'.
  518. 'ms' -> 'application/x-troff-ms'.
  519. 'msh' -> 'model/mesh'.
  520. 'msi' -> 'application/x-msi'.
  521. 'mvb' -> 'chemical/x-mopac-vib'.
  522. 'mxu' -> 'video/vnd.mpegurl'.
  523. 'nb' -> 'application/mathematica'.
  524. 'nc' -> 'application/x-netcdf'.
  525. 'nwc' -> 'application/x-nwc'.
  526. 'o' -> 'application/x-object'.
  527. 'oda' -> 'application/oda'.
  528. 'odb' -> 'application/vnd.oasis.opendocument.database'.
  529. 'odc' -> 'application/vnd.oasis.opendocument.chart'.
  530. 'odf' -> 'application/vnd.oasis.opendocument.formula'.
  531. 'odg' -> 'application/vnd.oasis.opendocument.graphics'.
  532. 'odi' -> 'application/vnd.oasis.opendocument.image'.
  533. 'odm' -> 'application/vnd.oasis.opendocument.text-master'.
  534. 'odp' -> 'application/vnd.oasis.opendocument.presentation'.
  535. 'ods' -> 'application/vnd.oasis.opendocument.spreadsheet'.
  536. 'odt' -> 'application/vnd.oasis.opendocument.text'.
  537. 'ogg' -> 'application/ogg'.
  538. 'old' -> 'application/x-trash'.
  539. 'oth' -> 'application/vnd.oasis.opendocument.text-web'.
  540. 'oza' -> 'application/x-oz-application'.
  541. 'p' -> 'text/x-pascal'.
  542. 'p7r' -> 'application/x-pkcs7-certreqresp'.
  543. 'pac' -> 'application/x-ns-proxy-autoconfig'.
  544. 'pas' -> 'text/x-pascal'.
  545. 'pat' -> 'image/x-coreldrawpattern'.
  546. 'pbm' -> 'image/x-portable-bitmap'.
  547. 'pcf' -> 'application/x-font'.
  548. 'pcf.Z' -> 'application/x-font'.
  549. 'pcx' -> 'image/pcx'.
  550. 'pdb' -> 'chemical/x-pdb'.
  551. 'pdf' -> 'application/pdf'.
  552. 'pfa' -> 'application/x-font'.
  553. 'pfb' -> 'application/x-font'.
  554. 'pgm' -> 'image/x-portable-graymap'.
  555. 'pgn' -> 'application/x-chess-pgn'.
  556. 'pgp' -> 'application/pgp-signature'.
  557. 'pk' -> 'application/x-tex-pk'.
  558. 'pl' -> 'text/x-perl'.
  559. 'pls' -> 'audio/x-scpls'.
  560. 'pm' -> 'text/x-perl'.
  561. 'png' -> 'image/png'.
  562. 'pnm' -> 'image/x-portable-anymap'.
  563. 'pot' -> 'text/plain'.
  564. 'ppm' -> 'image/x-portable-pixmap'.
  565. 'pps' -> 'application/vnd.ms-powerpoint'.
  566. 'ppt' -> 'application/vnd.ms-powerpoint'.
  567. 'prf' -> 'application/pics-rules'.
  568. 'prt' -> 'chemical/x-ncbi-asn1-ascii'.
  569. 'ps' -> 'application/postscript'.
  570. 'psd' -> 'image/x-photoshop'.
  571. 'psp' -> 'text/x-psp'.
  572. 'py' -> 'text/x-python'.
  573. 'pyc' -> 'application/x-python-code'.
  574. 'pyo' -> 'application/x-python-code'.
  575. 'qt' -> 'video/quicktime'.
  576. 'qtl' -> 'application/x-quicktimeplayer'.
  577. 'ra' -> 'audio/x-realaudio'.
  578. 'ram' -> 'audio/x-pn-realaudio'.
  579. 'rar' -> 'application/rar'.
  580. 'ras' -> 'image/x-cmu-raster'.
  581. 'rd' -> 'chemical/x-mdl-rdfile'.
  582. 'rdf' -> 'application/rdf+xml'.
  583. 'rgb' -> 'image/x-rgb'.
  584. 'rm' -> 'audio/x-pn-realaudio'.
  585. 'roff' -> 'application/x-troff'.
  586. 'ros' -> 'chemical/x-rosdal'.
  587. 'rpm' -> 'application/x-redhat-package-manager'.
  588. 'rss' -> 'application/rss+xml'.
  589. 'rtf' -> 'text/rtf'.
  590. 'rtx' -> 'text/richtext'.
  591. 'rxn' -> 'chemical/x-mdl-rxnfile'.
  592. 'sct' -> 'text/scriptlet'.
  593. 'sd' -> 'chemical/x-mdl-sdfile'.
  594. 'sd2' -> 'audio/x-sd2'.
  595. 'sda' -> 'application/vnd.stardivision.draw'.
  596. 'sdc' -> 'application/vnd.stardivision.calc'.
  597. 'sdd' -> 'application/vnd.stardivision.impress'.
  598. 'sdf' -> 'chemical/x-mdl-sdfile'.
  599. 'sdp' -> 'application/vnd.stardivision.impress'.
  600. 'sdw' -> 'application/vnd.stardivision.writer'.
  601. 'ser' -> 'application/java-serialized-object'.
  602. 'sgf' -> 'application/x-go-sgf'.
  603. 'sgl' -> 'application/vnd.stardivision.writer-global'.
  604. 'sh' -> 'text/x-sh'.
  605. 'shar' -> 'application/x-shar'.
  606. 'shtml' -> 'text/html'.
  607. 'sid' -> 'audio/prs.sid'.
  608. 'sik' -> 'application/x-trash'.
  609. 'silo' -> 'model/mesh'.
  610. 'sis' -> 'application/vnd.symbian.install'.
  611. 'sit' -> 'application/x-stuffit'.
  612. 'skd' -> 'application/x-koan'.
  613. 'skm' -> 'application/x-koan'.
  614. 'skp' -> 'application/x-koan'.
  615. 'skt' -> 'application/x-koan'.
  616. 'smf' -> 'application/vnd.stardivision.math'.
  617. 'smi' -> 'application/smil'.
  618. 'smil' -> 'application/smil'.
  619. 'snd' -> 'audio/basic'.
  620. 'spc' -> 'chemical/x-galactic-spc'.
  621. 'spl' -> 'application/x-futuresplash'.
  622. 'src' -> 'application/x-wais-source'.
  623. 'stc' -> 'application/vnd.sun.xml.calc.template'.
  624. 'std' -> 'application/vnd.sun.xml.draw.template'.
  625. 'sti' -> 'application/vnd.sun.xml.impress.template'.
  626. 'stl' -> 'application/vnd.ms-pki.stl'.
  627. 'stw' -> 'application/vnd.sun.xml.writer.template'.
  628. 'sty' -> 'text/x-tex'.
  629. 'sv4cpio' -> 'application/x-sv4cpio'.
  630. 'sv4crc' -> 'application/x-sv4crc'.
  631. 'svg' -> 'image/svg+xml'.
  632. 'svgz' -> 'image/svg+xml'.
  633. 'sw' -> 'chemical/x-swissprot'.
  634. 'swf' -> 'application/x-shockwave-flash'.
  635. 'swfl' -> 'application/x-shockwave-flash'.
  636. 'sxc' -> 'application/vnd.sun.xml.calc'.
  637. 'sxd' -> 'application/vnd.sun.xml.draw'.
  638. 'sxg' -> 'application/vnd.sun.xml.writer.global'.
  639. 'sxi' -> 'application/vnd.sun.xml.impress'.
  640. 'sxm' -> 'application/vnd.sun.xml.math'.
  641. 'sxw' -> 'application/vnd.sun.xml.writer'.
  642. 't' -> 'application/x-troff'.
  643. 'tar' -> 'application/x-tar'.
  644. 'taz' -> 'application/x-gtar'.
  645. 'tcl' -> 'text/x-tcl'.
  646. 'tex' -> 'text/x-tex'.
  647. 'texi' -> 'application/x-texinfo'.
  648. 'texinfo' -> 'application/x-texinfo'.
  649. 'text' -> 'text/plain'.
  650. 'tgf' -> 'chemical/x-mdl-tgf'.
  651. 'tgz' -> 'application/x-gtar'.
  652. 'tif' -> 'image/tiff'.
  653. 'tiff' -> 'image/tiff'.
  654. 'tk' -> 'text/x-tcl'.
  655. 'tm' -> 'text/texmacs'.
  656. 'torrent' -> 'application/x-bittorrent'.
  657. 'tr' -> 'application/x-troff'.
  658. 'ts' -> 'text/texmacs'.
  659. 'tsp' -> 'application/dsptype'.
  660. 'tsv' -> 'text/tab-separated-values'.
  661. 'txt' -> 'text/plain'.
  662. 'udeb' -> 'application/x-debian-package'.
  663. 'uls' -> 'text/iuls'.
  664. 'ustar' -> 'application/x-ustar'.
  665. 'val' -> 'chemical/x-ncbi-asn1-binary'.
  666. 'vcd' -> 'application/x-cdlink'.
  667. 'vcf' -> 'text/x-vcard'.
  668. 'vcs' -> 'text/x-vcalendar'.
  669. 'vmd' -> 'chemical/x-vmd'.
  670. 'vms' -> 'chemical/x-vamas-iso14976'.
  671. 'vor' -> 'application/vnd.stardivision.writer'.
  672. 'vrm' -> 'x-world/x-vrml'.
  673. 'vrml' -> 'x-world/x-vrml'.
  674. 'vsd' -> 'application/vnd.visio'.
  675. 'wad' -> 'application/x-doom'.
  676. 'wav' -> 'audio/x-wav'.
  677. 'wax' -> 'audio/x-ms-wax'.
  678. 'wbmp' -> 'image/vnd.wap.wbmp'.
  679. 'wbxml' -> 'application/vnd.wap.wbxml'.
  680. 'wk' -> 'application/x-123'.
  681. 'wm' -> 'video/x-ms-wm'.
  682. 'wma' -> 'audio/x-ms-wma'.
  683. 'wmd' -> 'application/x-ms-wmd'.
  684. 'wml' -> 'text/vnd.wap.wml'.
  685. 'wmlc' -> 'application/vnd.wap.wmlc'.
  686. 'wmls' -> 'text/vnd.wap.wmlscript'.
  687. 'wmlsc' -> 'application/vnd.wap.wmlscriptc'.
  688. 'wmv' -> 'video/x-ms-wmv'.
  689. 'wmx' -> 'video/x-ms-wmx'.
  690. 'wmz' -> 'application/x-ms-wmz'.
  691. 'wp5' -> 'application/wordperfect5.1'.
  692. 'wpd' -> 'application/wordperfect'.
  693. 'wrl' -> 'x-world/x-vrml'.
  694. 'wsc' -> 'text/scriptlet'.
  695. 'wvx' -> 'video/x-ms-wvx'.
  696. 'wz' -> 'application/x-wingz'.
  697. 'xbm' -> 'image/x-xbitmap'.
  698. 'xcf' -> 'application/x-xcf'.
  699. 'xht' -> 'application/xhtml+xml'.
  700. 'xhtml' -> 'application/xhtml+xml'.
  701. 'xlb' -> 'application/vnd.ms-excel'.
  702. 'xls' -> 'application/vnd.ms-excel'.
  703. 'xlt' -> 'application/vnd.ms-excel'.
  704. 'xml' -> 'application/xml'.
  705. 'xpi' -> 'application/x-xpinstall'.
  706. 'xpm' -> 'image/x-xpixmap'.
  707. 'xsl' -> 'application/xml'.
  708. 'xtel' -> 'chemical/x-xtel'.
  709. 'xul' -> 'application/vnd.mozilla.xul+xml'.
  710. 'xwd' -> 'image/x-xwindowdump'.
  711. 'xyz' -> 'chemical/x-xyz'.
  712. 'zip' -> 'application/zip'.
  713. 'zmt' -> 'chemical/x-mopac-input'.
  714. '~' -> 'application/x-trash'
  715. }
  716. !
  717. defaultPort
  718. ^4000
  719. !
  720. mimeTypeFor: aString
  721. ^self mimeTypes at: (aString replace: '.*[\.]' with: '') ifAbsent: ['text/plain']
  722. !
  723. mimeTypes
  724. ^mimeTypes ifNil: [mimeTypes := self defaultMimeTypes]
  725. !
  726. printHelp
  727. console log: 'Available commandline options are:'.
  728. console log: '--help'.
  729. self commandLineSwitches do: [ :each |
  730. console log: each, ' <parameter>']
  731. !
  732. selectorForCommandLineSwitch: aSwitch
  733. "Remove the trailing '--', add ':' at the end
  734. and replace all occurences of a lowercase letter preceded by a '-' with
  735. the Uppercase letter.
  736. Example: --fallback-page becomes fallbackPage:"
  737. ^((aSwitch replace: '^--' with: '')
  738. replace: '-[a-z]' with: [ :each | each second asUppercase ]), ':'
  739. ! !
  740. !FileServer class methodsFor: 'initialization'!
  741. createServerWithArguments: options
  742. "If options are empty return a default FileServer instance.
  743. If options are given loop through them and set the passed in values
  744. on the FileServer instance.
  745. Commanline options map directly to methods in the 'accessing' protocol
  746. taking one parameter.
  747. Adding a method to this protocol makes it directly settable through
  748. command line options.
  749. "
  750. | server popFront front optionName optionValue switches |
  751. switches := self commandLineSwitches.
  752. server := self new.
  753. options ifEmpty: [^server].
  754. (options size even) ifFalse: [
  755. console log: 'Using default parameters.'.
  756. console log: 'Wrong commandline options or not enough arguments for: ' , options.
  757. console log: 'Use any of the following ones: ', switches.
  758. ^server].
  759. popFront := [:args |
  760. front := args first.
  761. args remove: front.
  762. front].
  763. [options notEmpty] whileTrue: [
  764. optionName := popFront value: options.
  765. optionValue := popFront value: options.
  766. (switches includes: optionName) ifTrue: [
  767. optionName := self selectorForCommandLineSwitch: optionName.
  768. server perform: optionName withArguments: (Array with: optionValue)]
  769. ifFalse: [
  770. console log: optionName, ' is not a valid commandline option'.
  771. console log: 'Use any of the following ones: ', switches ]].
  772. ^server.
  773. !
  774. main
  775. "Main entry point for Amber applications.
  776. Creates and starts a FileServer instance."
  777. | fileServer args |
  778. args := process argv.
  779. "Remove the first args which contain the path to the node executable and the script file."
  780. args removeFrom: 1 to: 3.
  781. args detect: [ :each |
  782. (each = '--help') ifTrue: [FileServer printHelp]]
  783. ifNone: [
  784. fileServer := FileServer createServerWithArguments: args.
  785. ^fileServer start]
  786. ! !
  787. Object subclass: #Repl
  788. instanceVariableNames: 'readline interface util'
  789. package: 'AmberCli'!
  790. !Repl commentStamp!
  791. I am a class representing a REPL (Read Evaluate Print Loop) and provide a command line interface to Amber Smalltalk.
  792. On the prompt you can type Amber statements which will be evaluated after pressing <Enter>.
  793. The evaluation is comparable with executing a 'DoIt' in a workspace.
  794. My runtime requirement is a functional Node.js executable with working Readline support.!
  795. !Repl methodsFor: 'accessing'!
  796. prompt
  797. ^'amber >> '
  798. ! !
  799. !Repl methodsFor: 'actions'!
  800. close
  801. process stdin destroy
  802. !
  803. createInterface
  804. "No completion for now"
  805. interface := readline createInterface: process stdin stdout: process stdout.
  806. interface on: 'line' do: [:buffer | self eval: buffer].
  807. interface on: 'close' do: [self close].
  808. self setPrompt.
  809. interface prompt
  810. !
  811. eval: buffer
  812. | result |
  813. buffer isEmpty ifFalse: [
  814. self try: [
  815. result := Compiler new evaluateExpression: buffer.
  816. Transcript show: result]
  817. catch: [:e |
  818. e isSmalltalkError
  819. ifTrue: [ErrorHandler new handleError: e]
  820. ifFalse: [process stdout write: e jsStack]]].
  821. interface prompt
  822. !
  823. setPrompt
  824. interface setPrompt: self prompt
  825. ! !
  826. !Repl methodsFor: 'initialization'!
  827. initialize
  828. super initialize.
  829. readline := require value: 'readline'.
  830. util := require value: 'util'
  831. ! !
  832. !Repl class methodsFor: 'not yet classified'!
  833. main
  834. self new createInterface
  835. ! !