Contents of /trunk/coreutils/patches-5.3.0/coreutils-5.3.0-gen-progress-bar.patch
Parent Directory | Revision Log
Revision 44 -
(show annotations)
(download)
Thu Oct 13 21:17:16 2005 UTC (18 years, 11 months ago) by niro
File size: 12049 byte(s)
Thu Oct 13 21:17:16 2005 UTC (18 years, 11 months ago) by niro
File size: 12049 byte(s)
patch set for coretutils-5.3.0
1 | Upstream has been contacted about this a few times ... |
2 | |
3 | they dont want progress bars in mv/cp: |
4 | http://lists.gnu.org/archive/html/bug-coreutils/2003-08/msg00114.html |
5 | http://lists.gnu.org/archive/html/bug-coreutils/2003-09/msg00083.html |
6 | http://lists.gnu.org/archive/html/bug-coreutils/2003-09/msg00084.html |
7 | |
8 | but they don't seem to mind a general util ... add this to future patchset: |
9 | http://lists.gnu.org/archive/html/bug-coreutils/2003-09/msg00101.html |
10 | http://lists.gnu.org/archive/html/bug-coreutils/2004-02/msg00071.html |
11 | |
12 | diff -urN 1/src/copy.c 2/src/copy.c |
13 | --- 1/src/copy.c 2004-09-20 08:27:12.000000000 +0100 |
14 | +++ 2/src/copy.c 2005-03-26 15:53:57.000000000 +0000 |
15 | @@ -17,6 +17,8 @@ |
16 | |
17 | /* Extracted from cp.c and librarified by Jim Meyering. */ |
18 | |
19 | +/* Progress bar support added by Miika Pekkarinen. miipekk@ihme.org */ |
20 | + |
21 | #include <config.h> |
22 | #include <stdio.h> |
23 | #include <assert.h> |
24 | @@ -26,6 +28,10 @@ |
25 | # include <hurd.h> |
26 | #endif |
27 | |
28 | +#ifdef GWINSZ_IN_SYS_IOCTL |
29 | +# include <sys/ioctl.h> |
30 | +#endif |
31 | + |
32 | #include "system.h" |
33 | #include "backupfile.h" |
34 | #include "copy.h" |
35 | @@ -44,3 +50,4 @@ |
36 | #include "savedir.h" |
37 | #include "utimens.h" |
38 | +#include "xstrtol.h" |
39 | #include "xreadlink.h" |
40 | @@ -80,6 +87,8 @@ |
41 | /* Initial size of the above hash table. */ |
42 | #define DEST_INFO_INITIAL_CAPACITY 61 |
43 | |
44 | +#define SAMPLE_MAX 10 |
45 | + |
46 | static bool copy_internal (const char *src_path, const char *dst_path, |
47 | bool new_dst, dev_t device, |
48 | struct dir_list *ancestors, |
49 | @@ -186,6 +195,62 @@ |
50 | return ok; |
51 | } |
52 | |
53 | +/* Shorten a string '/long path/long file' to 'long fi...' |
54 | + Also adds padding bytes to end of the string if necessary */ |
55 | +char *shorten_path(const char *str, int max_width) |
56 | +{ |
57 | + char *shortname; |
58 | + char *filename = (char *) (rindex(str, '/')); |
59 | + int len; |
60 | + |
61 | + if (filename == NULL) |
62 | + { |
63 | + filename = (char *) str; |
64 | + } |
65 | + else |
66 | + { |
67 | + filename = (char *) &filename[1]; |
68 | + } |
69 | + |
70 | + len = strlen(filename); |
71 | + shortname = (char *) xmalloc (max_width + 1); |
72 | + strncpy (shortname, filename, max_width); |
73 | + shortname[max_width] = '\0'; |
74 | + if (len > max_width) |
75 | + { |
76 | + memset(&shortname[max_width - 3], '.', 3); |
77 | + } |
78 | + else |
79 | + { |
80 | + memset(&shortname[len], ' ', max_width - len); |
81 | + } |
82 | + |
83 | + return shortname; |
84 | +} |
85 | + |
86 | +char *si_units(off_t size) |
87 | +{ |
88 | + const static int buf_size = 20; |
89 | + char *buf; |
90 | + static char *unit_array[] = { "B", "KiB", "MiB", "GiB", "" }; |
91 | + int i; |
92 | + |
93 | + buf = xmalloc(20); |
94 | + for (i = 0; size > 10000; i++) |
95 | + { |
96 | + if (unit_array[i][0] == '\0') |
97 | + { |
98 | + i--; |
99 | + break; |
100 | + } |
101 | + size /= 1024; |
102 | + } |
103 | + |
104 | + snprintf (buf, buf_size, "%lu %s", (unsigned long)size, unit_array[i]); |
105 | + |
106 | + return buf; |
107 | +} |
108 | + |
109 | /* Copy a regular file from SRC_PATH to DST_PATH. |
110 | If the source file contains holes, copies holes and blocks of zeros |
111 | in the source file as holes in the destination file. |
112 | @@ -214,6 +279,19 @@ |
113 | off_t n_read_total = 0; |
114 | bool last_write_made_hole = false; |
115 | bool make_holes = false; |
116 | + time_t t_start; |
117 | + time_t t_last; |
118 | + time_t t_now; |
119 | + int last_bytes = 0; |
120 | + int progress_bar_printed = 0; |
121 | + char *shortname = NULL; |
122 | + off_t sample_window[SAMPLE_MAX]; |
123 | + off_t sample_sum = 0; |
124 | + int sample_count = 0; |
125 | + int line_length = 0; |
126 | +#ifdef TIOCGWINSZ |
127 | + struct winsize ws; |
128 | +#endif |
129 | |
130 | source_desc = open (src_path, O_RDONLY); |
131 | if (source_desc < 0) |
132 | @@ -318,6 +396,9 @@ |
133 | buf = alloca (buf_size + sizeof (int) + buf_alignment - 1); |
134 | buf = ptr_align (buf, buf_alignment); |
135 | |
136 | + time (&t_start); |
137 | + t_last = t_start; |
138 | + |
139 | for (;;) |
140 | { |
141 | ssize_t n_read = read (source_desc, buf, buf_size); |
142 | @@ -382,6 +463,113 @@ |
143 | } |
144 | last_write_made_hole = false; |
145 | } |
146 | + |
147 | + time (&t_now); |
148 | + |
149 | + /* Progress bar stuff */ |
150 | + if (! x->pbar_show || t_now - t_start < x->pbar_delay) |
151 | + { |
152 | + continue; |
153 | + } |
154 | + |
155 | + if (! progress_bar_printed) |
156 | + { |
157 | + /* Column width check code copied from ls.c */ |
158 | + char const *p = getenv ("COLUMNS"); |
159 | + if (p && *p) |
160 | + { |
161 | + long int tmp_long; |
162 | + if (xstrtol (p, NULL, 0, &tmp_long, NULL) == LONGINT_OK |
163 | + && 0 < tmp_long && tmp_long <= INT_MAX) |
164 | + { |
165 | + line_length = (int) tmp_long; |
166 | + } |
167 | + else |
168 | + { |
169 | + error (0, 0, |
170 | + _("ignoring invalid width in environment \ |
171 | + variable COLUMNS: %s"), |
172 | + quotearg (p)); |
173 | + } |
174 | + } |
175 | + |
176 | +#ifdef TIOCGWINSZ |
177 | + if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0) |
178 | + { |
179 | + line_length = ws.ws_col; |
180 | + } |
181 | +#endif |
182 | + if (line_length < 50) |
183 | + { |
184 | + continue; |
185 | + } |
186 | + |
187 | + /* Take a short filename for progress bar */ |
188 | + shortname = shorten_path(src_path, line_length - 48); |
189 | + progress_bar_printed = 1; |
190 | + } |
191 | + |
192 | + if (t_now == t_last) |
193 | + { |
194 | + continue; |
195 | + } |
196 | + |
197 | + if (sample_count == SAMPLE_MAX) |
198 | + { |
199 | + int i; |
200 | + |
201 | + sample_sum -= sample_window[0]; |
202 | + for (i = 0; i < SAMPLE_MAX - 1; i++) |
203 | + { |
204 | + sample_window[i] = sample_window[i + 1]; |
205 | + } |
206 | + } |
207 | + else |
208 | + { |
209 | + sample_count++; |
210 | + } |
211 | + |
212 | + { |
213 | + char *str_size; |
214 | + char *str_speed; |
215 | + char etabuf[64]; |
216 | + time_t t_temp; |
217 | + |
218 | + sample_window[sample_count - 1] = (n_read_total - last_bytes) / |
219 | + (t_now - t_last); |
220 | + sample_sum += sample_window[sample_count - 1]; |
221 | + |
222 | + /* Calculate the remaining time */ |
223 | + t_temp = (src_open_sb.st_size - n_read_total) / (sample_sum / sample_count); |
224 | + |
225 | + /* Don't print the progress bar if the estimated remaining |
226 | + time is low. */ |
227 | + if (progress_bar_printed == 1 && t_temp < x->pbar_min_est) |
228 | + { |
229 | + continue; |
230 | + } |
231 | + progress_bar_printed = 2; |
232 | + |
233 | + str_size = si_units(src_open_sb.st_size); |
234 | + str_speed = si_units(sample_sum / sample_count); |
235 | + |
236 | + strftime(etabuf, sizeof etabuf, "%H:%M.%S", |
237 | + gmtime(&t_temp)); |
238 | + printf (_("%s | %3d%% | %9s | %9s/s | ETA %s\r"), shortname, |
239 | + (int)(n_read_total * 100 / src_open_sb.st_size), |
240 | + str_size, str_speed, etabuf); |
241 | + fflush (stdout); |
242 | + free(str_size); |
243 | + free(str_speed); |
244 | + t_last = t_now; |
245 | + last_bytes = n_read_total; |
246 | + } |
247 | + } |
248 | + |
249 | + /* Print a newline if progress bar is enabled and has been shown */ |
250 | + if (progress_bar_printed == 2) |
251 | + { |
252 | + printf ("%s | 100%%\n", shortname); |
253 | } |
254 | |
255 | /* If the file ends with a `hole', something needs to be written at |
256 | @@ -418,6 +606,11 @@ |
257 | return_val = false; |
258 | } |
259 | |
260 | + if (shortname != NULL) |
261 | + { |
262 | + free (shortname); |
263 | + } |
264 | + |
265 | return return_val; |
266 | } |
267 | |
268 | diff -urN 1/src/copy.h 2/src/copy.h |
269 | --- 1/src/copy.h 2004-11-26 09:03:45.000000000 +0000 |
270 | +++ 2/src/copy.h 2005-03-26 15:44:50.000000000 +0000 |
271 | @@ -154,6 +154,16 @@ |
272 | /* If true, display the names of the files before copying them. */ |
273 | bool verbose; |
274 | |
275 | + /* If true, display a progress bar when the following conditions are |
276 | + * met: |
277 | + - pbar_delay defines how many seconds to wait before considering to |
278 | + display the progress bar |
279 | + - pbar_min_est defines how many seconds estimated operation complete |
280 | + time should be at least to show the progress bar. */ |
281 | + bool pbar_show; |
282 | + int pbar_delay; |
283 | + int pbar_min_est; |
284 | + |
285 | /* If true, stdin is a tty. */ |
286 | bool stdin_tty; |
287 | |
288 | diff -urN 1/src/cp.c 2/src/cp.c |
289 | --- 1/src/cp.c 2004-10-10 20:10:09.000000000 +0100 |
290 | +++ 2/src/cp.c 2005-03-26 15:46:00.000000000 +0000 |
291 | @@ -84,6 +84,14 @@ |
292 | /* Initial number of entries in the inode hash table. */ |
293 | #define INITIAL_ENTRY_TAB_SIZE 70 |
294 | |
295 | +/* Initial settings for progress bar when it's enabled. |
296 | + PROGRESS_DELAY defines how many seconds to wait before even |
297 | + considering to display a proggress bar. |
298 | + PROGRESS_MIN_EST defines how many seconds estimated operation |
299 | + complete time should be at least to show the progress bar. */ |
300 | +#define PROGRESS_DELAY 5 |
301 | +#define PROGRESS_MIN_EST 5 |
302 | + |
303 | /* The invocation name of this program. */ |
304 | char *program_name; |
305 | |
306 | @@ -123,6 +131,7 @@ |
307 | {"copy-contents", no_argument, NULL, COPY_CONTENTS_OPTION}, |
308 | {"dereference", no_argument, NULL, 'L'}, |
309 | {"force", no_argument, NULL, 'f'}, |
310 | + {"progress", no_argument, NULL, 'g'}, |
311 | {"interactive", no_argument, NULL, 'i'}, |
312 | {"link", no_argument, NULL, 'l'}, |
313 | {"no-dereference", no_argument, NULL, 'P'}, |
314 | @@ -180,6 +189,8 @@ |
315 | --no-dereference never follow symbolic links\n\ |
316 | -f, --force if an existing destination file cannot be\n\ |
317 | opened, remove it and try again\n\ |
318 | + -g, --progress show a progress bar if operation is going to\n\ |
319 | + take a long time\n\ |
320 | -i, --interactive prompt before overwrite\n\ |
321 | -H follow command-line symbolic links\n\ |
322 | "), stdout); |
323 | @@ -711,6 +722,11 @@ |
324 | |
325 | x->update = false; |
326 | x->verbose = false; |
327 | + |
328 | + x->pbar_show = false; |
329 | + x->pbar_delay = PROGRESS_DELAY; |
330 | + x->pbar_min_est = PROGRESS_MIN_EST; |
331 | + |
332 | x->dest_info = NULL; |
333 | x->src_info = NULL; |
334 | } |
335 | @@ -817,7 +833,7 @@ |
336 | we'll actually use backup_suffix_string. */ |
337 | backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); |
338 | |
339 | - while ((c = getopt_long (argc, argv, "abdfHilLprst:uvxPRS:TV:", |
340 | + while ((c = getopt_long (argc, argv, "abdfgHilLprst:uvxPRS:TV:", |
341 | long_opts, NULL)) |
342 | != -1) |
343 | { |
344 | @@ -887,6 +903,10 @@ |
345 | case NO_PRESERVE_ATTRIBUTES_OPTION: |
346 | decode_preserve_arg (optarg, &x, false); |
347 | break; |
348 | + |
349 | + case 'g': |
350 | + x.pbar_show = 1; |
351 | + break; |
352 | |
353 | case PRESERVE_ATTRIBUTES_OPTION: |
354 | if (optarg == NULL) |
355 | diff -urN 1/src/mv.c 2/src/mv.c |
356 | --- 1/src/mv.c 2004-09-22 13:41:20.000000000 +0100 |
357 | +++ 2/src/mv.c 2005-03-26 15:48:35.000000000 +0000 |
358 | @@ -45,6 +45,14 @@ |
359 | /* Initial number of entries in the inode hash table. */ |
360 | #define INITIAL_ENTRY_TAB_SIZE 70 |
361 | |
362 | +/* Initial settings for progress bar when it's enabled. |
363 | + PROGRESS_DELAY defines how many seconds to wait before even |
364 | + considering to display a proggress bar. |
365 | + PROGRESS_MIN_EST defines how many seconds estimated operation |
366 | + complete time should be at least to show the progress bar. */ |
367 | +#define PROGRESS_DELAY 5 |
368 | +#define PROGRESS_MIN_EST 5 |
369 | + |
370 | /* For long options that have no equivalent short option, use a |
371 | non-character as a pseudo short option, starting with CHAR_MAX + 1. */ |
372 | enum |
373 | @@ -75,6 +83,7 @@ |
374 | { |
375 | {"backup", optional_argument, NULL, 'b'}, |
376 | {"force", no_argument, NULL, 'f'}, |
377 | + {"progress", no_argument, NULL, 'g'}, |
378 | {"interactive", no_argument, NULL, 'i'}, |
379 | {"no-target-directory", no_argument, NULL, 'T'}, |
380 | {"reply", required_argument, NULL, REPLY_OPTION}, |
381 | @@ -143,6 +152,10 @@ |
382 | |
383 | x->update = false; |
384 | x->verbose = false; |
385 | + x->pbar_show = false; |
386 | + x->pbar_delay = PROGRESS_DELAY; |
387 | + x->pbar_min_est = PROGRESS_MIN_EST; |
388 | + |
389 | x->dest_info = NULL; |
390 | x->src_info = NULL; |
391 | } |
392 | @@ -313,6 +326,8 @@ |
393 | -b like --backup but does not accept an argument\n\ |
394 | -f, --force do not prompt before overwriting\n\ |
395 | (equivalent to --reply=yes)\n\ |
396 | + -g, --progress show a progress bar if operation is going to\n\ |
397 | + take a long time\n\ |
398 | -i, --interactive prompt before overwrite\n\ |
399 | (equivalent to --reply=query)\n\ |
400 | "), stdout); |
401 | @@ -357,6 +372,9 @@ |
402 | int c; |
403 | bool ok; |
404 | bool make_backups = false; |
405 | + bool pbar_show = false; |
406 | + int pbar_delay = PROGRESS_DELAY; |
407 | + int pbar_min_est = PROGRESS_MIN_EST; |
408 | char *backup_suffix_string; |
409 | char *version_control_string = NULL; |
410 | struct cp_options x; |
411 | @@ -379,7 +397,7 @@ |
412 | we'll actually use backup_suffix_string. */ |
413 | backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); |
414 | |
415 | - while ((c = getopt_long (argc, argv, "bfit:uvS:TV:", long_options, NULL)) |
416 | + while ((c = getopt_long (argc, argv, "bfgit:uvS:TV:", long_options, NULL)) |
417 | != -1) |
418 | { |
419 | switch (c) |
420 | @@ -399,6 +417,9 @@ |
421 | case 'f': |
422 | x.interactive = I_ALWAYS_YES; |
423 | break; |
424 | + case 'g': |
425 | + x.pbar_show = 1; |
426 | + break; |
427 | case 'i': |
428 | x.interactive = I_ASK_USER; |
429 | break; |