febootstrap: Use contents of installed Debian packages instead of downloading and...
[febootstrap.git] / src / febootstrap_pacman.ml
1 (* febootstrap 3
2  * Copyright (C) 2009-2010 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  *)
18
19 (* ArchLinux support. *)
20
21 open Unix
22 open Printf
23
24 open Febootstrap_package_handlers
25 open Febootstrap_utils
26 open Febootstrap_cmdline
27
28 (* Create a temporary directory for use by all the functions in this file. *)
29 let tmpdir = tmpdir ()
30
31 let pacman_detect () =
32   file_exists "/etc/arch-release" &&
33     Config.pacman <> "no"
34
35 let pacman_resolve_dependencies_and_download names =
36   let cmd =
37     sprintf "pactree -u %s | sort -u"
38       (String.concat " " (List.map Filename.quote names)) in
39   let pkgs = run_command_get_lines cmd in
40
41   (* Exclude packages matching [--exclude] regexps on the command line. *)
42   let pkgs =
43     List.filter (
44       fun name ->
45         not (List.exists (fun re -> Str.string_match re name 0) excludes)
46     ) pkgs in
47
48   (* Download the packages. I could use wget `pacman -Sp`, but this
49    * narrows the pacman -Sy window
50    *)
51   List.iter (
52     fun pkg ->
53       let cmd =
54         sprintf "umask 0000; cd %s && mkdir -p var/lib/pacman && fakeroot pacman -Syw --noconfirm --cachedir=$(pwd) --root=$(pwd) %s"
55         (Filename.quote tmpdir)
56         pkg in
57       if Sys.command cmd <> 0 then (
58           (* The package is not in the main repos, check the aur *)
59           let cmd =
60             sprintf "umask 0000; cd %s && wget http://aur.archlinux.org/packages/%s/%s.tar.gz && tar xf %s.tar.gz && cd %s && makepkg && mv %s-*.pkg.tar.xz %s"
61             (Filename.quote tmpdir)
62             pkg
63             pkg
64             pkg
65             pkg
66             pkg
67             (Filename.quote tmpdir) in
68           run_command cmd;
69         )
70   ) pkgs;
71
72   List.sort compare pkgs
73
74 let pacman_list_files ?(use_installed=false) pkg =
75   if use_installed then
76     failwith "pacman driver doesn't support --use-installed";
77
78   debug "unpacking %s ..." pkg;
79
80   (* We actually need to extract the file in order to get the
81    * information about modes etc.
82    *)
83   let pkgdir = tmpdir // pkg ^ ".d" in
84   mkdir pkgdir 0o755;
85   let cmd =
86     sprintf "pacman -Q %s | awk '{print $2}'"
87       pkg in
88    let ver = List.hd (run_command_get_lines cmd) in
89    let cmd =
90      sprintf "umask 0000; fakeroot tar -xf %s-%s* -C %s"
91      (Filename.quote tmpdir // pkg ) ver (Filename.quote pkgdir) in
92    run_command cmd;
93
94   let cmd = sprintf "cd %s && find ." pkgdir in
95   let lines = run_command_get_lines cmd in
96
97   let files = List.map (
98     fun path ->
99       assert (path.[0] = '.');
100       (* No leading '.' *)
101       let path =
102         if path = "." then "/"
103         else String.sub path 1 (String.length path - 1) in
104
105       (* Find out what it is and get the canonical filename. *)
106       let statbuf = lstat (pkgdir // path) in
107       let is_dir = statbuf.st_kind = S_DIR in
108
109       (* No per-file metadata like in RPM, but we can synthesize it
110        * from the path.
111        *)
112       let config = statbuf.st_kind = S_REG && string_prefix "/etc/" path in
113
114       let mode = statbuf.st_perm in
115
116       (path, { ft_dir = is_dir; ft_config = config; ft_mode = mode;
117                ft_ghost = false; ft_size = statbuf.st_size })
118   ) lines in
119
120   files
121
122 (* Easy because we already unpacked the archive above. *)
123 let pacman_get_file_from_package ?(use_installed=false) pkg file =
124   if use_installed then
125     failwith "pacman driver doesn't support --use-installed";
126
127   tmpdir // pkg ^ ".d" // file
128
129 let () =
130   let ph = {
131     ph_detect = pacman_detect;
132     ph_resolve_dependencies_and_download =
133       pacman_resolve_dependencies_and_download;
134     ph_list_files = pacman_list_files;
135     ph_get_file_from_package = pacman_get_file_from_package;
136   } in
137   register_package_handler "pacman" ph