windows-installer.scm 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Mike Sperber
  3. ; This produces the auto-generated part of the Windows installer
  4. ; source code.
  5. (define *non-slashes* (char-set-complement (char-set #\/)))
  6. ; returns a pair of directory (itself a list) and base file name
  7. (define (split-file-name f)
  8. (let ((rev-components (reverse (string-tokenize f *non-slashes*))))
  9. (cons (reverse (cdr rev-components))
  10. (car rev-components))))
  11. (define (write-file-elements-include-file file-names uuids output-file-name)
  12. (call-with-output-file output-file-name
  13. (lambda (port)
  14. (display "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" port)
  15. (newline port)
  16. (display "<Include>" port)
  17. (newline port)
  18. (write-file-elements file-names uuids port)
  19. (display "</Include>" port)
  20. (newline port))))
  21. ; organize the directories into a tree
  22. ; returns a tree = list of (union string (cons subdir tree))
  23. (define (tree-ize-directory-alist alist)
  24. (call-with-values
  25. (lambda ()
  26. (partition (lambda (pair) (null? (car pair))) alist))
  27. (lambda (file-pairs directory-pairs)
  28. (let* ((prefixes (delete-duplicates (map caar directory-pairs)))
  29. (subdirectories
  30. (map (lambda (prefix)
  31. (let* ((with-prefix-pairs
  32. (filter (lambda (pair)
  33. (string=? prefix (caar pair)))
  34. directory-pairs))
  35. (omit-prefix
  36. (map (lambda (pair)
  37. (cons (cdar pair) (cdr pair)))
  38. with-prefix-pairs)))
  39. (cons prefix (tree-ize-directory-alist omit-prefix))))
  40. prefixes)))
  41. (append subdirectories (concatenate (map cdr file-pairs)))))))
  42. ; write the WiX file elements for a given list of file names
  43. (define (write-file-elements file-names uuids port)
  44. (let* ((split-names (map split-file-name file-names))
  45. (directories (delete-duplicates (map car split-names)))
  46. (alist
  47. (map (lambda (directory)
  48. (cons directory
  49. (filter-map (lambda (split-name)
  50. (if (equal? directory (car split-name))
  51. (cdr split-name)
  52. #f))
  53. split-names)))
  54. directories))
  55. (tree (tree-ize-directory-alist alist)))
  56. (write-directory-tree '() tree (make-uuid-source uuids) port)))
  57. (define (make-uuid-source uuids)
  58. (lambda ()
  59. (let ((uuid (car uuids)))
  60. (set! uuids (cdr uuids))
  61. uuid)))
  62. (define (write-directory-tree directory alist uuid-source port)
  63. (if (not (null? directory))
  64. (begin
  65. (display "<Directory Id=\"" port)
  66. (display (directory-id directory) port)
  67. (display "\" Name=\"" port)
  68. (display (car (reverse directory)) port)
  69. (display "\" >" port)
  70. (newline port)))
  71. (call-with-values
  72. (lambda () (partition string? alist))
  73. (lambda (file-names directory-entries)
  74. (if (not (null? file-names))
  75. (begin
  76. (display "<Component Id=\"" port)
  77. (display (component-id directory) port)
  78. (display "\" Guid=\"" port)
  79. (display (uuid-source) port)
  80. (display "\">" port)
  81. (newline port)
  82. (let ((used-file-names (list '()))) ; poor man's cell
  83. (for-each (lambda (file-name)
  84. (write-file-element port directory file-name used-file-names))
  85. file-names))
  86. (display "</Component>" port)
  87. (newline port)))
  88. (for-each (lambda (entry)
  89. (write-directory-tree (append directory (list (car entry)))
  90. (cdr entry)
  91. uuid-source
  92. port))
  93. directory-entries)))
  94. (if (not (null? directory))
  95. (begin
  96. (display "</Directory>" port)
  97. (newline port))))
  98. (define (quote-component comp)
  99. (list->string
  100. (map (lambda (ch)
  101. (if (char=? ch #\-)
  102. #\.
  103. ch))
  104. (string->list comp))))
  105. ; insert separators between the components
  106. (define (components->string directory separator)
  107. (let ((id #f))
  108. (for-each (lambda (component)
  109. (if id
  110. (set! id (string-append id separator component))
  111. (set! id component)))
  112. directory)
  113. id))
  114. (define (components->quoted-string dir sep)
  115. (components->string (map quote-component dir) sep))
  116. (define (directory-id directory)
  117. (components->quoted-string directory "_"))
  118. (define (file-id directory base)
  119. (components->quoted-string (append directory (list base)) "_"))
  120. (define (file-src directory base)
  121. (components->string (append directory (list base)) "/"))
  122. (define (component-id directory)
  123. (components->quoted-string (append directory (list "component")) "_"))
  124. (define (write-file-element port directory base-name used-file-names)
  125. (display "<File Id=\"" port)
  126. (display (file-id directory base-name) port)
  127. (display "\" Name=\"" port)
  128. (display base-name port)
  129. (display "\" Source=\"" port)
  130. (display (file-src directory base-name) port)
  131. (display "\" DiskId=\"1\" Vital=\"yes\" />" port)
  132. (newline port))