Skip to content

Commit d807b3c

Browse files
committed
Initial commit.
0 parents  commit d807b3c

36 files changed

+12617
-0
lines changed

Makefile

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
all: system-file-magic depcheck
2+
3+
depcheck: asdf.lisp depcheck.lisp
4+
buildapp --dynamic-space-size 4000 --output depcheck --load asdf.lisp --require sb-aclrepl --require sb-bsd-sockets --require sb-rt --require sb-cover --require sb-sprof --entry depcheck:main --require sb-introspect --require sb-cltl2 --require sb-posix --require sb-concurrency --load depcheck.lisp
5+
6+
7+
system-file-magic: asdf.lisp system-file-magic.lisp
8+
buildapp --dynamic-space-size 4000 --output system-file-magic --load asdf.lisp --require sb-posix --load system-file-magic.lisp --entry system-file-magic:main
9+
10+
install: system-file-magic depcheck
11+
install -c -m 555 system-file-magic $(HOME)/bin
12+
install -c -m 555 depcheck $(HOME)/bin
13+
14+
clean:
15+
rm -f system-file-magic depcheck

README

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
The Quicklisp Controller is responsible for building and updating
2+
Quicklisp distributions from a project list (maintained separately in
3+
the quicklisp-projects repo).
4+
5+
It fetches project source from a variety of places: git, cvs, svn,
6+
http-available tarballs, etc, and uses that to build up metadata about
7+
the relationships between projects. New or updated projects are then
8+
uploaded into the quicklisp download space.
9+
10+
You must create ~/quicklisp-controller/ and symlink a checkout of
11+
quicklisp-projects (or something with similar directory structure) to
12+
~/quicklisp-controller/projects. A quick way to do that:
13+
14+
(setup-directories "~/path/to/quicklisp-projects/")
15+
16+
To fetch/update all project sources, use:
17+
18+
(update-what-you-can)
19+
20+
To build everything that can be built, use:
21+
22+
(ensure-what-wins-you-can)
23+
24+
To combine those two operations, concluding with a report of what
25+
differs from the last Quicklisp dist:
26+
27+
(recrank)
28+

asdf.lisp

+9,807
Large diffs are not rendered by default.

client-uploader.lisp

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
;;;; client-uploader.lisp
2+
3+
(in-package #:quicklisp-controller)
4+
5+
(defparameter *quickstart-bucket* "beta.quicklisp.org")
6+
7+
(defun invalidate-quickstart-paths (paths)
8+
(let ((distributions (zs3:distributions-for-bucket *quickstart-bucket*))
9+
(paths (mapcar (lambda (path)
10+
(if (char= (char path 0) #\/)
11+
path
12+
(format nil "/~A" path)))
13+
paths)))
14+
(dolist (distribution distributions)
15+
(zs3:invalidate-paths distribution paths))))
16+
17+
(defun upload-client-files ()
18+
(with-posix-cwd "~/src/quicklisp-client/"
19+
(run "make")
20+
(let* ((version (first-line-of "version.txt"))
21+
(versioned-key (format nil "quickstart/quicklisp-~A.tgz" version)))
22+
(zs3:put-file "quicklisp.tar"
23+
*quickstart-bucket* "quickstart/quicklisp.tar"
24+
:public t)
25+
(zs3:put-file (file-namestring versioned-key)
26+
*quickstart-bucket* versioned-key
27+
:public t)
28+
(zs3:put-file "version.txt" *quickstart-bucket* "quickstart/version.txt"
29+
:public t :content-type "text/plain")
30+
(invalidate-quickstart-paths (list "/quickstart/version.txt"
31+
"/quickstart/quicklisp.tar"
32+
versioned-key)))))
33+
34+
(defun upload-bootstrap-files ()
35+
(with-posix-cwd "~/src/quicklisp-bootstrap/"
36+
(zs3:put-file "asdf.lisp"
37+
*quickstart-bucket*
38+
"quickstart/asdf.lisp"
39+
:public t
40+
:content-type "text/plain")
41+
(zs3:put-file "quicklisp.lisp" *quickstart-bucket* "quicklisp.lisp"
42+
:public t
43+
:content-type "text/plain"
44+
:content-disposition "attachment")
45+
(zs3:put-file "setup.lisp" *quickstart-bucket* "quickstart/setup.lisp"
46+
:public t
47+
:content-type "text/plain")
48+
(invalidate-quickstart-paths '("/quicklisp.lisp"
49+
"/quickstart/asdf.lisp"
50+
"/quickstart/setup.lisp"))))

commands.lisp

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
;;;; commands.lisp
2+
3+
(in-package #:quicklisp-controller)
4+
5+
(defvar *command-output* (make-synonym-stream '*standard-output*))
6+
7+
(define-condition run-error (error)
8+
((command
9+
:initarg :command
10+
:reader run-error-command)
11+
(arguments
12+
:initarg :arguments
13+
:reader run-error-arguments)
14+
(exit-code
15+
:initarg :exit-code
16+
:reader run-error-exit-code))
17+
(:report (lambda (condition stream)
18+
(format stream "Run error (exit code ~D) for:~% ~S ~{~S~^ ~}"
19+
(run-error-exit-code condition)
20+
(run-error-command condition)
21+
(run-error-arguments condition)))))
22+
23+
(defun stringify-command-argument (argument)
24+
(typecase argument
25+
(null nil)
26+
(string argument)
27+
(pathname (native-namestring argument))
28+
(keyword (format nil "--~(~A~)" argument))
29+
(t (princ-to-string argument))))
30+
31+
(defun run (command &rest arguments)
32+
(let* ((arguments (remove nil
33+
(mapcar #'stringify-command-argument arguments)))
34+
(process (run-program command arguments
35+
:search t
36+
:wait t
37+
:output *command-output*)))
38+
(unwind-protect
39+
(let ((code (process-exit-code process)))
40+
(if (zerop code)
41+
t
42+
(error 'run-error
43+
:exit-code code
44+
:command command
45+
:arguments arguments)))
46+
(ignore-errors (process-close process)))))
47+
48+
(defmacro with-run-output ((stream (command &rest args)) &body body)
49+
`(let* ((*command-output* (make-string-output-stream)))
50+
(run ,command ,@args)
51+
(with-input-from-string (,stream (get-output-stream-string *command-output*))
52+
,@body)))
53+
54+
(defun native-directory-string (pathname)
55+
(native-namestring (directory-namestring (probe-file pathname))))
56+
57+
(defmacro with-posix-cwd (new-directory &body body)
58+
;; fchdir thing from Linux's getcwd(3)
59+
(let ((fd (gensym))
60+
(new (gensym)))
61+
`(let ((,fd nil)
62+
(,new (native-directory-string ,new-directory)))
63+
(unwind-protect
64+
(let ((*default-pathname-defaults* (probe-file ,new)))
65+
(setf ,fd (sb-posix:open "." 0))
66+
(sb-posix:chdir ,new)
67+
,@body)
68+
(when ,fd
69+
(sb-posix:fchdir ,fd)
70+
(ignore-errors (sb-posix:close ,fd)))))))
71+
72+
(defmacro with-binary-run-output (pathname &body body)
73+
`(with-open-file (*command-output* ,pathname :direction :output
74+
:element-type '(unsigned-byte 8)
75+
:if-exists :supersede)
76+
,@body))
77+
78+
(defmacro without-run-output (&body body)
79+
`(let ((*command-output* nil))
80+
,@body))
81+
82+
(defun run-output-lines (command &rest args)
83+
(let ((output (with-output-to-string (*command-output*)
84+
(apply #'run command args))))
85+
(with-input-from-string (stream output)
86+
(loop for line = (read-line stream nil)
87+
while line collect line))))

config.lisp

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
;;;; config.lisp
2+
3+
(in-package #:quicklisp-controller)
4+
5+
(defvar *report-to-email* nil
6+
"The email address to which reports are emailed.")

depcheck.lisp

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
;;; depcheck.lisp
2+
3+
(defpackage #:depcheck
4+
(:use #:cl))
5+
6+
(in-package #:depcheck)
7+
8+
(defvar *direct-dependencies* nil)
9+
10+
(defun load-asdf-system-table (file)
11+
(let ((table (make-hash-table :test 'equalp)))
12+
(with-open-file (stream file)
13+
(loop for line = (read-line stream nil)
14+
while line do
15+
(let ((pathname
16+
(merge-pathnames line
17+
file)))
18+
(setf (gethash (pathname-name pathname) table)
19+
(truename pathname)))))
20+
table))
21+
22+
(defvar *systems* nil)
23+
24+
(defun real-system-name (name)
25+
(setf name (string name))
26+
(subseq name 0 (position #\/ name)))
27+
28+
(defun system-finder (name)
29+
(when *systems*
30+
(gethash (real-system-name name) *systems*)))
31+
32+
(defun sbcl-contrib-p (name)
33+
(and (<= 3 (length name))
34+
(string= name "sb-" :end1 3)))
35+
36+
(defun normalize-dependency (name)
37+
(cond ((and (consp name)
38+
(keywordp (first name)))
39+
(string-downcase (second name)))
40+
((or (symbolp name) (stringp name))
41+
(string-downcase name))
42+
(t (error "Don't know how to normalize ~S" name))))
43+
44+
(defun make-hook (old-hook system-name)
45+
(lambda (fun form env)
46+
(when (and (consp form)
47+
(eq (first form) 'asdf:defsystem)
48+
(string-equal (second form) system-name))
49+
(let ((deps (getf (cddr form) :depends-on))
50+
(prereqs (getf (cddr form) :defsystem-depends-on))
51+
(weak (getf (cddr form) :weakly-depends-on)))
52+
(setf deps (append deps prereqs weak))
53+
(setf *direct-dependencies* (mapcar 'normalize-dependency deps))))
54+
(funcall old-hook fun form env)))
55+
56+
(defvar *in-find-system* nil)
57+
(defvar *implied-dependencies* nil)
58+
59+
(defvar *load-op-wrapper*
60+
'(defmethod asdf:operate :around ((op (eql 'asdf:load-op)) system
61+
&key &allow-other-keys)
62+
(cond (*in-find-system*
63+
(push (asdf::coerce-name system) *implied-dependencies*)
64+
(let ((*in-find-system* nil))
65+
(call-next-method)))
66+
(t
67+
(call-next-method)))))
68+
69+
(defvar *metadata-required-p* nil)
70+
71+
(defun check-system-metadata (system)
72+
(when *metadata-required-p*
73+
(flet ((check-attribute (fun description)
74+
(let ((value (funcall fun system)))
75+
(cond ((not value)
76+
(error "Missing ~A for system ~A"
77+
description
78+
(asdf:component-name system)))
79+
((and (stringp value) (zerop (length value)))
80+
(error "Empty ~A for system ~A"
81+
description
82+
(asdf:component-name system))))
83+
(when (and (stringp value) (zerop (length value)))))))
84+
(check-attribute 'asdf:system-description :description)
85+
;; Not yet
86+
;;(check-attribute 'asdf:system-license :license)
87+
(check-attribute 'asdf:system-author :author))))
88+
89+
(defun compute-dependencies (system-file system-name)
90+
(let* ((asdf:*system-definition-search-functions*
91+
(list #-asdf3 'asdf::sysdef-find-asdf
92+
'system-finder))
93+
(dependencies nil)
94+
(*direct-dependencies* nil)
95+
(*macroexpand-hook* (make-hook *macroexpand-hook* system-name)))
96+
(let ((*implied-dependencies* nil)
97+
(*in-find-system* t))
98+
(check-system-metadata (asdf:find-system system-file))
99+
(setf dependencies *implied-dependencies*))
100+
(asdf:oos 'asdf:load-op system-name)
101+
(setf dependencies
102+
(remove-duplicates (append *direct-dependencies* dependencies)
103+
:test #'equalp))
104+
(sort (remove-if #'sbcl-contrib-p dependencies) #'string<)))
105+
106+
(defun magic (system-file system trace-file)
107+
(handler-bind ((sb-ext:defconstant-uneql #'continue))
108+
(with-open-file (stream trace-file :direction :output
109+
:if-exists :supersede)
110+
(format stream "~A~{ ~A~}~%"
111+
system (compute-dependencies system-file system)))))
112+
113+
(defun main (argv)
114+
(setf *print-pretty* nil)
115+
(sb-posix:setenv "SBCL_HOME"
116+
(load-time-value
117+
(directory-namestring sb-int::*core-string*))
118+
1)
119+
(sb-posix:setenv "CC" "gcc" 1)
120+
(eval *load-op-wrapper*)
121+
(destructuring-bind (index project system dependency-file errors-file
122+
&optional *metadata-required-p*)
123+
(rest argv)
124+
(setf *systems* (load-asdf-system-table index))
125+
(with-open-file (*error-output* errors-file
126+
:if-exists :supersede
127+
:direction :output)
128+
(unless (sb-posix:getenv "DEPCHECK_DEBUG")
129+
(sb-ext:disable-debugger))
130+
(unwind-protect
131+
(magic project system dependency-file)
132+
(ignore-errors (close *error-output*))))
133+
(when (probe-file dependency-file)
134+
(delete-file errors-file))))
135+

descriptions.lisp

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
;;;; descriptions.lisp
2+
3+
(in-package #:quicklisp-controller)
4+
5+
;;;
6+
;;; Create a description .cdb file for a mock dist
7+
;;; based on the dist build descriptions file
8+
;;;
9+
10+
(defun descriptions-table ()
11+
(let ((table (make-string-table)))
12+
(with-open-file (stream #p"qlc:descriptions.txt")
13+
(loop for (system description) = (read stream nil)
14+
while system do
15+
(when (plusp (length description))
16+
(setf (gethash system table) description))))
17+
table))
18+
19+
(defun encode-description (string)
20+
(let ((octets (babel:string-to-octets string :encoding :utf-8)))
21+
(remove-if (lambda (code)
22+
(< code 32))
23+
octets)))
24+
25+
(defun write-dist-descriptions-cdb (dist-name)
26+
(let* ((dist (or (ql-dist:dist dist-name)
27+
(error "Unknown dist ~S" dist-name)))
28+
(file (ql-dist:relative-to dist "descriptions.cdb"))
29+
(tmp (ql-dist:relative-to dist "descriptions.tmp"))
30+
(descriptions (descriptions-table)))
31+
(zcdb:with-output-to-cdb (cdb file tmp)
32+
(dolist (system (ql-dist:provided-systems dist))
33+
(let* ((name (ql-dist:name system))
34+
(description (gethash name descriptions)))
35+
(restart-bind ((skip (lambda (&optional val)
36+
(declare (ignore val))
37+
(go :skip))))
38+
(when description
39+
(zcdb:add-record (ascii-encode name)
40+
(encode-description description)
41+
cdb))))
42+
:skip))))

0 commit comments

Comments
 (0)