2 * Copyright (C) 2009-2011 Red Hat Inc.
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.
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.
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
24 open Febootstrap_package_handlers
25 open Febootstrap_utils
26 open Febootstrap_cmdline
28 (* Create a temporary directory for use by all the functions in this file. *)
29 let tmpdir = tmpdir ()
31 let get_installed_pkgs =
32 let pkgs = ref None in
37 Some (run_command_get_lines
38 "dpkg-query --show --showformat='${Package}\\n'");
44 let debian_detect () =
45 file_exists "/etc/debian_version" &&
46 Config.aptitude <> "no" && Config.apt_cache <> "no" && Config.dpkg <> "no"
48 let rec debian_resolve_dependencies_and_download names =
50 sprintf "%s depends --recurse -i %s | grep -v '^[<[:space:]]'"
52 (String.concat " " (List.map Filename.quote names)) in
53 let pkgs = run_command_get_lines cmd in
55 if Config.apt_cache_depends_recurse_broken then
56 workaround_broken_apt_cache_depends_recurse (sort_uniq pkgs)
60 (* Exclude packages matching [--exclude] regexps on the command line. *)
64 not (List.exists (fun re -> Str.string_match re name 0) excludes)
67 let present_pkgs, download_pkgs = List.partition (
68 fun pkg -> List.exists ((=) pkg) (get_installed_pkgs ())
71 debug "wanted packages (present / download): %s / %s\n"
72 (String.concat " " present_pkgs)
73 (String.concat " " download_pkgs);
75 (* Download the packages. *)
76 if (List.length download_pkgs > 0)
79 sprintf "umask 0000; cd %s && %s download %s"
80 (Filename.quote tmpdir)
82 (String.concat " " (List.map Filename.quote download_pkgs)) in
86 (* Find out what aptitude downloaded. *)
87 let files = Sys.readdir tmpdir in
89 let download_pkgs = List.map (
91 (* Look for 'pkg_*.deb' in the list of files. *)
92 let pre = pkg ^ "_" in
95 for i = 0 to Array.length files - 1 do
96 if string_prefix pre files.(i) then (
102 eprintf "febootstrap: aptitude: error: no file was downloaded corresponding to package %s\n" pkg;
108 List.sort compare (List.append present_pkgs download_pkgs)
110 (* On Ubuntu 10.04 LTS, apt-cache depends --recurse is broken. It
111 * doesn't return the full list of dependencies. Therefore recurse
112 * into these dependencies one by one until we reach a fixpoint.
114 and workaround_broken_apt_cache_depends_recurse names =
115 debug "workaround for broken 'apt-cache depends --recurse' command:\n %s"
116 (String.concat " " names);
122 sprintf "%s depends --recurse -i %s | grep -v '^[<[:space:]]'"
123 Config.apt_cache (Filename.quote name) in
124 run_command_get_lines cmd
126 let names' = List.flatten names' in
127 let names' = sort_uniq names' in
128 if names <> names' then
129 workaround_broken_apt_cache_depends_recurse names'
133 let debian_list_files_downloaded pkg =
134 debug "unpacking %s ..." pkg;
136 (* We actually need to extract the file in order to get the
137 * information about modes etc.
139 let pkgdir = tmpdir // pkg ^ ".d" in
142 sprintf "umask 0000; dpkg-deb --fsys-tarfile %s | (cd %s && tar xf -)"
143 (tmpdir // pkg) pkgdir in
146 let cmd = sprintf "cd %s && find ." pkgdir in
147 let lines = run_command_get_lines cmd in
149 let files = List.map (
151 assert (path.[0] = '.');
154 if path = "." then "/"
155 else String.sub path 1 (String.length path - 1) in
157 (* Find out what it is and get the canonical filename. *)
158 let statbuf = lstat (pkgdir // path) in
159 let is_dir = statbuf.st_kind = S_DIR in
161 (* No per-file metadata like in RPM, but we can synthesize it
164 let config = statbuf.st_kind = S_REG && string_prefix "/etc/" path in
166 let mode = statbuf.st_perm in
168 (path, { ft_dir = is_dir; ft_config = config; ft_mode = mode;
169 ft_ghost = false; ft_size = statbuf.st_size })
174 let debian_list_files_installed pkg =
175 debug "using installed package %s ..." pkg;
176 let cmd = sprintf "dpkg-query --listfiles %s" pkg in
177 let lines = run_command_get_lines cmd in
178 (* filter out lines not directly describing fs objects such as
179 "package diverts others to: /path/to/..." *)
180 let lines = List.filter (
181 fun l -> l.[0] = '/' && l.[1] != '.'
183 let files = List.map (
185 let statbuf = lstat path in
186 let is_dir = statbuf.st_kind = S_DIR in
187 let config = statbuf.st_kind = S_REG && string_prefix "/etc/" path in
188 let mode = statbuf.st_perm in
189 (path, { ft_dir = is_dir; ft_config = config; ft_mode = mode;
190 ft_ghost = false; ft_size = statbuf.st_size })
194 let debian_list_files ?(use_installed=false) pkg =
195 if use_installed && List.exists ((=) pkg) (get_installed_pkgs ()) then
196 debian_list_files_installed pkg
198 debian_list_files_downloaded pkg
200 (* Easy because we already unpacked the archive above. *)
201 let debian_get_file_from_package ?(use_installed=false) pkg file =
202 if use_installed && List.exists (fun p -> p = pkg) (get_installed_pkgs ())
206 tmpdir // pkg ^ ".d" // file
210 ph_detect = debian_detect;
211 ph_resolve_dependencies_and_download =
212 debian_resolve_dependencies_and_download;
213 ph_list_files = debian_list_files;
214 ph_get_file_from_package = debian_get_file_from_package;
216 register_package_handler "debian" ph