Annotation of /trunk/coreutils/patches-5.3.0/coreutils-5.3.0-gen-progress-bar.patch
Parent Directory | Revision Log
Revision 44 -
(hide 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 | niro | 44 | 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; |