OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [ecosadmin.tcl] - Blame information for rev 851

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
#!/usr/bin/env tclsh
2
 
3
# {{{  Banner
4
 
5
#===============================================================================
6
#
7
#       ecosadmin.tcl
8
#
9
#       A package install/uninstall tool.
10
#
11
#===============================================================================
12
## ####ECOSGPLCOPYRIGHTBEGIN####                                            
13
## -------------------------------------------                              
14
## This file is part of eCos, the Embedded Configurable Operating System.   
15
## Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2009 Free Software Foundation, Inc.
16
##
17
## eCos is free software; you can redistribute it and/or modify it under    
18
## the terms of the GNU General Public License as published by the Free     
19
## Software Foundation; either version 2 or (at your option) any later      
20
## version.                                                                 
21
##
22
## eCos is distributed in the hope that it will be useful, but WITHOUT      
23
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
24
## FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
25
## for more details.                                                        
26
##
27
## You should have received a copy of the GNU General Public License        
28
## along with eCos; if not, write to the Free Software Foundation, Inc.,    
29
## 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
30
##
31
## As a special exception, if other files instantiate templates or use      
32
## macros or inline functions from this file, or you compile this file      
33
## and link it with other works to produce a work based on this file,       
34
## this file does not by itself cause the resulting work to be covered by   
35
## the GNU General Public License. However the source code for this file    
36
## must still be made available in accordance with section (3) of the GNU   
37
## General Public License v2.                                               
38
##
39
## This exception does not invalidate any other reasons why a work based    
40
## on this file might be covered by the GNU General Public License.         
41
## -------------------------------------------                              
42
## ####ECOSGPLCOPYRIGHTEND####                                              
43
#===============================================================================
44
######DESCRIPTIONBEGIN####
45
#
46
# Author(s):    jld
47
# Contributors: bartv
48
# Date:         1999-06-18
49
# Purpose:      To install and uninstall packages from an eCos component
50
#               repository
51
# Description:
52
# Usage:
53
#
54
#####DESCRIPTIONEND####
55
#===============================================================================
56
#
57
 
58
# }}}
59
# {{{  Version check
60
 
61
# ----------------------------------------------------------------------------
62
# ecosadmin.tcl requires at least version 8.0 of Tcl, since it makes use of
63
# namespaces. It is possible that some users still have older versions.
64
 
65
if { [info tclversion] < 8.0 } {
66
        puts "This script requires Tcl 8.0 or later. You are running Tcl [info patchlevel]."
67
        return
68
}
69
 
70
# }}}
71
# {{{  Namespace definition
72
 
73
# ----------------------------------------------------------------------------
74
# Namespaces. All code and variables in this script are kept in the namespace
75
# "ecosadmin". This is not really necessary for stand-alone operation, but if it
76
# ever becomes desirable to embed this script in a larger application then
77
# using a namespace is a lot easier.
78
#
79
# As a fringe benefit, all global variables can be declared inside this
80
# namespace and initialised.
81
#
82
 
83
namespace eval ecosadmin {
84
 
85
        # Is this program running under Windows ?
86
        variable windows_host [expr {$tcl_platform(platform) == "windows"}]
87
        variable null_device ""
88
        if { $windows_host != 0 } {
89
                set ecosadmin::null_device "nul"
90
        } else {
91
                set ecosadmin::null_device "/dev/null"
92
        }
93
 
94
 
95
        # Where is the component repository ? The following input sources
96
        # are available:
97
        # 1) the environment variable ECOS_REPOSITORY.
98
        # 2) $argv0 should correspond to the location of the ecosadmin.tcl
99
        #    script.
100
        #
101
        variable component_repository ""
102
        if { [info exists ::env(ECOS_REPOSITORY)] } {
103
                # override the calculation of the repository location using the 
104
                # (undocumented) ECOS_REPOSITORY environment variable
105
                set component_repository $::env(ECOS_REPOSITORY)
106
        } else {
107
                set component_repository [pwd]
108
                if { [file dirname $argv0] != "." } {
109
                        set component_repository [file join $component_repository [file dirname $argv0]]
110
                }
111
        }
112
 
113
        # Details of the command line arguments, if any.
114
        variable list_packages_arg   0;     # list
115
        variable clean_database_arg  0;     # clean
116
        variable check_database_arg  0;     # check
117
        variable accept_license_arg  0;     # --accept_license
118
        variable extract_license_arg 0;     # --extract_license
119
        variable add_package        "";     # add FILE
120
        variable remove_package     "";     # remove PACKAGE
121
        variable keep_targets_arg    1;     # --keep_targets, --remove_targets
122
        variable merge_repository   "";     # merge REPOSITORY
123
        variable version_arg        "";     # --version VER
124
 
125
        # Details of all known packages, targets and templates
126
        # read from the ecos.db file
127
        variable known_packages ""
128
        variable known_targets ""
129
        variable known_templates ""
130
        array set package_data {};
131
        array set target_data {};
132
        array set template_data {};
133
 
134
        # List of packages merged from another repository
135
        variable merge_packages ""
136
 
137
        # What routines should be invoked for outputting fatal errors and
138
        # for warning messages ?
139
        variable fatal_error_handler ecosadmin::cli_fatal_error
140
        variable warning_handler     ecosadmin::cli_warning
141
        variable report_handler      ecosadmin::cli_report
142
 
143
        # Keep or remove the CVS directories?
144
        variable keep_cvs 0
145
}
146
 
147
# }}}
148
# {{{  Infrastructure
149
 
150
# ----------------------------------------------------------------------------
151
# Minimal infrastructure support.
152
#
153
# There must be some way of reporting fatal errors, of outputting warnings,
154
# and of generating report messages. The implementation of these things
155
# obviously depends on whether or not TK is present. In addition, if this
156
# script is being run inside a larger application then that larger
157
# application must be able to install its own versions of the routines.
158
#
159
# Once it is possible to report fatal errors, an assertion facility becomes
160
# feasible.
161
#
162
# These routines output fatal errors, warnings or miscellaneous messages.
163
# Their implementations depend on the mode in which this script is operating.
164
#
165
proc ecosadmin::fatal_error { msg } {
166
        $ecosadmin::fatal_error_handler "$msg"
167
}
168
 
169
proc ecosadmin::warning { msg } {
170
        $ecosadmin::warning_handler "$msg"
171
}
172
 
173
proc ecosadmin::report { msg } {
174
        $ecosadmin::report_handler "$msg"
175
}
176
 
177
#
178
# Command line versions.
179
# NOTE: some formatting so that there are linebreaks at ~72 columns would be
180
# a good idea.
181
#
182
proc ecosadmin::cli_fatal_error_handler { msg } {
183
        error "$msg"
184
}
185
 
186
proc ecosadmin::cli_warning_handler { msg } {
187
        puts "ecosadmin warning: $msg"
188
}
189
 
190
proc ecosadmin::cli_report_handler { msg } {
191
        puts "$msg"
192
}
193
 
194
#
195
# Determine the default destination for warnings and for fatal errors.
196
# After the first call to this function it is possible to use assertions.
197
#
198
proc ecosadmin::initialise_error_handling { } {
199
        set ecosadmin::fatal_error_handler ecosadmin::cli_fatal_error_handler
200
        set ecosadmin::warning_handler     ecosadmin::cli_warning_handler
201
        set ecosadmin::report_handler      ecosadmin::cli_report_handler
202
}
203
 
204
#
205
# These routines can be used by containing programs to provide their
206
# own error handling.
207
#
208
proc ecosadmin::set_fatal_error_handler { fn } {
209
        ASSERT { $fn != "" }
210
        set ecosadmin::fatal_error_handler $fn
211
}
212
 
213
proc ecosadmin::set_warning_handler { fn } {
214
        ASSERT { $fn != "" }
215
        set ecosadmin::warning_handler $fn
216
}
217
 
218
proc ecosadmin::set_report_handler { fn } {
219
        ASSERT { $fn != "" }
220
        set ecosadmin::report_handler $fn
221
}
222
 
223
#
224
# A very simple assertion facility. It takes a single argument, an expression
225
# that should be evaluated in the calling function's scope, and on failure it
226
# should generate a fatal error.
227
#
228
proc ecosadmin::ASSERT { condition } {
229
        set result [uplevel 1 [list expr $condition]]
230
 
231
        if { $result == 0 } {
232
                fatal_error "assertion predicate \"$condition\"\nin \"[info level -1]\""
233
        }
234
}
235
 
236
# }}}
237
# {{{  Utilities
238
 
239
# ----------------------------------------------------------------------------
240
# cdl_compare_version. This is a partial implementation of the full
241
# cdl_compare_version facility defined in the product specification. Its
242
# purpose is to order the various versions of a given package with
243
# the most recent version first. As a special case, "current" is
244
# always considered the most recent.
245
#
246
# There are similarities between cdl_compare_version and with Tcl's
247
# package vcompare, but cdl_compare_version is more general.
248
#
249
 
250
proc ecosadmin::cdl_compare_version { arg1 arg2 } {
251
 
252
        if { $arg1 == $arg2 } {
253
                return 0
254
        }
255
        if { $arg1 == "current"} {
256
                return -1
257
        }
258
        if { $arg2 == "current" } {
259
                return 1
260
        }
261
 
262
        set index1 0
263
        set index2 0
264
        set ch1    ""
265
        set ch2    ""
266
        set num1   ""
267
        set num2   ""
268
 
269
        while { 1 } {
270
 
271
                set ch1 [string index $arg1 $index1]
272
                set ch2 [string index $arg2 $index2]
273
                set num1 ""
274
                set num2 ""
275
 
276
                if { ($ch1 == "") && ($ch2 == "") } {
277
 
278
                        # Both strings have terminated at the same time. There may have
279
                        # been some spurious leading zeroes in numbers.
280
                        return 0
281
 
282
                } elseif { $ch1 == "" } {
283
 
284
                        # The first string has ended first. If ch2 is a separator then
285
                        # arg2 is a derived version, e.g. v0.3.p1 and hence newer. Otherwise ch2
286
                        # is an experimental version v0.3beta and hence older.
287
                        if { [string match \[-._\] $ch2] } {
288
                                return 1
289
                        } else {
290
                                return -1
291
                        }
292
                } elseif { $ch2 == "" } {
293
 
294
                        # Equivalent to the above.
295
                        if { [string match \[-._\] $ch1] } {
296
                                return -1
297
                        } else {
298
                                return 1
299
                        }
300
                }
301
 
302
                # There is still data to be processed.
303
                # Check for both strings containing numbers at the current index.
304
                if { ( [string match \[0-9\] $ch1] ) && ( [string match \[0-9\] $ch2] ) } {
305
 
306
                        # Extract the entire numbers from the version string.
307
                        while { [string match \[0-9\] $ch1] } {
308
                                set  num1 "$num1$ch1"
309
                                incr index1
310
                                set  ch1 [string index $arg1 $index1]
311
                        }
312
                        while { [string match \[0-9\] $ch2] } {
313
                                set  num2 "$num2$ch2"
314
                                incr index2
315
                                set ch2 [string index $arg2 $index2]
316
                        }
317
 
318
                        if { $num1 < $num2 } {
319
                                return 1
320
                        } elseif { $num1 > $num2 } {
321
                                return -1
322
                        }
323
                        continue
324
                }
325
 
326
                # This is not numerical data. If the two characters are the same then
327
                # move on.
328
                if { $ch1 == $ch2 } {
329
                        incr index1
330
                        incr index2
331
                        continue
332
                }
333
 
334
                # Next check if both strings are at a separator. All separators can be
335
                # used interchangeably.
336
                if { ( [string match \[-._\] $ch1] ) && ( [string match \[-._\] $ch2] ) } {
337
                        incr index1
338
                        incr index2
339
                        continue
340
                }
341
 
342
                # There are differences in the characters and they are not interchangeable.
343
                # Just return a standard string comparison.
344
                return [string compare $ch1 $ch2]
345
        }
346
}
347
 
348
# }}}
349
# {{{  Argument parsing
350
 
351
# ----------------------------------------------------------------------------
352
# The argv0 argument should be the name of this script. It can be used
353
# to get at the component repository location. If this script has been
354
# run incorrectly then currently it will fail: in future it may be
355
# desirable to check an environment variable instead.
356
#
357
# The argv argument is a string containing the rest of the arguments.
358
# If any of the arguments contain spaces then this argument will be
359
# surrounded by braces. If any of the arguments contain braces then
360
# things will break.
361
#
362
 
363
proc ecosadmin::parse_arguments { argv0 argv } {
364
 
365
        if { $argv != "" } {
366
 
367
                # There are arguments. If any of the arguments contained
368
                # spaces then these arguments will have been surrounded
369
                # by braces, which is a nuisance. So start by turning the
370
                # arguments into a numerically indexed array.
371
 
372
                set argc 0
373
                array set args { }
374
                foreach arg $argv {
375
                        set args([incr argc]) $arg
376
                }
377
 
378
                # Now examine each argument with regular expressions. It is
379
                # useful to have some variables filled in by the regexp
380
                # matching.
381
                set dummy  ""
382
                set match1 ""
383
                set match2 ""
384
                for { set i 1 } { $i <= $argc } { incr i } {
385
 
386
                        # Check for --list and the other simple ones.
387
                        if { [regexp -- {^-?-?list$} $args($i)] == 1 } {
388
                                set ecosadmin::list_packages_arg 1
389
                                continue
390
                        }
391
 
392
                        # check for the clean command
393
                        if { [regexp -- {^-?-?clean$} $args($i)] == 1 } {
394
                                set ecosadmin::clean_database_arg 1
395
                                continue
396
                        }
397
 
398
                        # check for the check command
399
                        if { [regexp -- {^-?-?check$} $args($i)] == 1 } {
400
                                set ecosadmin::check_database_arg 1
401
                                continue
402
                        }
403
 
404
                        # check for --version
405
                        if { [regexp -- {^-?-version=?(.*)$} $args($i) dummy match1] == 1 } {
406
                                if { $match1 != "" } {
407
                                        set ecosadmin::version_arg $match1
408
                                } else {
409
                                        if { $i == $argc } {
410
                                                fatal_error "missing argument after --version"
411
                                        } else {
412
                                                set ecosadmin::version_arg $args([incr i])
413
                                        }
414
                                }
415
                                continue
416
                        }
417
 
418
                        # check for --accept_license
419
                        if { [regexp -- {^-?-accept_license$} $args($i)] == 1 } {
420
                                set ecosadmin::accept_license_arg 1
421
                                continue
422
                        }
423
 
424
                        # check for --extract_license
425
                        if { [regexp -- {^-?-extract_license$} $args($i)] == 1 } {
426
                                set ecosadmin::extract_license_arg 1
427
                                continue
428
                        }
429
 
430
                        # check for --keep_targets
431
                        if { [regexp -- {^-?-keep_targets$} $args($i)] == 1 } {
432
                                set ecosadmin::keep_targets_arg 1
433
                                continue
434
                        }
435
 
436
                        # check for --remove_targets
437
                        if { [regexp -- {^-?-remove_targets$} $args($i)] == 1 } {
438
                                set ecosadmin::keep_targets_arg 0
439
                                continue
440
                        }
441
 
442
                        # check for the add command
443
                        if { [regexp -- {^-?-?add=?(.*)$} $args($i) dummy match1] == 1 } {
444
                                if { $match1 != "" } {
445
                                        set ecosadmin::add_package $match1
446
                                } else {
447
                                        if { $i == $argc } {
448
                                                fatal_error "missing argument after add"
449
                                        } else {
450
                                                set ecosadmin::add_package $args([incr i])
451
                                        }
452
                                }
453
                                continue
454
                        }
455
 
456
                        # check for the merge command
457
                        if { [regexp -- {^-?-?merge=?(.*)$} $args($i) dummy match1] == 1 } {
458
                                if { $match1 != "" } {
459
                                        set ecosadmin::merge_repository $match1
460
                                } else {
461
                                        if { $i == $argc } {
462
                                                fatal_error "missing argument after merge"
463
                                        } else {
464
                                                set ecosadmin::merge_repository $args([incr i])
465
                                        }
466
                                }
467
                                continue
468
                        }
469
 
470
                        # check for the remove command
471
                        if { [regexp -- {^-?-?remove=?(.*)$} $args($i) dummy match1] == 1 } {
472
                                if { $match1 != "" } {
473
                                        set ecosadmin::remove_package $match1
474
                                } else {
475
                                        if { $i == $argc } {
476
                                                fatal_error "missing argument after remove"
477
                                        } else {
478
                                                set ecosadmin::remove_package $args([incr i])
479
                                        }
480
                                }
481
                                continue
482
                        }
483
 
484
                        # Check for --srcdir
485
                        if { [regexp -- {^-?-srcdir=?([ \.\\/:_a-zA-Z0-9-]*)$} $args($i) dummy match1] == 1 } {
486
                                if { $match1 == "" } {
487
                                        if { $i == $argc } {
488
                                                puts "ecosrelease: missing argument after --srcdir"
489
                                                exit 1
490
                                        } else {
491
                                                set match1 $args([incr i])
492
                                        }
493
                                }
494
                                set ecosadmin::component_repository $match1
495
                                continue
496
                        }
497
 
498
                        # An unrecognised argument.
499
                        fatal_error "invalid argument $args($i)"
500
                }
501
        }
502
 
503
        # Convert user-specified UNIX-style Cygwin pathnames to Windows Tcl-style as necessary
504
        set ecosadmin::component_repository [get_pathname_for_tcl $ecosadmin::component_repository]
505
        set ecosadmin::add_package [get_pathname_for_tcl $ecosadmin::add_package]
506
        set ecosadmin::merge_repository [get_pathname_for_tcl $ecosadmin::merge_repository]
507
}
508
 
509
#
510
# Display help information if the user has typed --help, -H, --H, or -help.
511
# The help text uses two hyphens for consistency with configure.
512
# Arguably this should change.
513
 
514
proc ecosadmin::argument_help { } {
515
 
516
        puts "Usage: ecosadmin \[ command \]"
517
        puts "  commands are:"
518
        puts "    list                                                   : list packages"
519
        puts "    check                                                  : check database"
520
        puts "    add FILE                                               : add packages"
521
        puts "    remove PACKAGE \[ --version VER \] \[ --remove_targets \]  : remove a package"
522
}
523
 
524
# }}}
525
# {{{  Packages file
526
 
527
proc ecosadmin::read_data { silentflag } {
528
 
529
        ASSERT { $ecosadmin::component_repository != "" }
530
 
531
        set ecosadmin::known_packages ""
532
        set ecosadmin::known_targets ""
533
        set ecosadmin::known_templates ""
534
 
535
        # A safe interpreter is used to process the packages file.
536
        # This is somewhat overcautious, but it is also harmless.
537
        # The following two commands are made accessible to the slave
538
        # interpreter and are responsible for updating the actual data.
539
        proc add_known_package { name } {
540
                lappend ::ecosadmin::known_packages $name
541
        }
542
        proc add_known_target { name } {
543
                lappend ::ecosadmin::known_targets $name
544
        }
545
        proc add_known_template { name } {
546
                lappend ::ecosadmin::known_templates $name
547
        }
548
        proc set_package_data { name value } {
549
                set ::ecosadmin::package_data($name) $value
550
        }
551
        proc set_target_data { name value } {
552
                set ::ecosadmin::target_data($name) $value
553
        }
554
        proc set_template_data { name value } {
555
                set ::ecosadmin::template_data($name) $value
556
        }
557
 
558
        # Create the parser, add the aliased commands, and then define
559
        # the routines that do the real work.
560
        set parser [interp create -safe]
561
        $parser alias add_known_package ecosadmin::add_known_package
562
        $parser alias add_known_target ecosadmin::add_known_target
563
        $parser alias add_known_template ecosadmin::add_known_template
564
        $parser alias set_package_data  ecosadmin::set_package_data
565
        $parser alias set_target_data  ecosadmin::set_target_data
566
        $parser alias set_template_data  ecosadmin::set_template_data
567
 
568
        $parser eval {
569
 
570
        set current_package ""
571
        set current_target ""
572
        set current_template ""
573
 
574
        proc package { name body } {
575
                add_known_package $name
576
                set_package_data "$name,alias" ""
577
                set_package_data "$name,versions" ""
578
                set_package_data "$name,dir" ""
579
                set_package_data "$name,hardware" 0
580
                set ::current_package $name
581
                eval $body
582
                set ::current_package ""
583
        }
584
 
585
        proc target { name body } {
586
                add_known_target $name
587
                set_target_data "$name,packages" ""
588
                set ::current_target $name
589
                eval $body
590
                set ::current_target ""
591
        }
592
 
593
#if 0
594
        # templates are no longer specified in the package database
595
        proc template { name body } {
596
                add_known_template $name
597
                set_template_data "$name,packages" ""
598
                set ::current_template $name
599
                eval $body
600
                set ::current_template ""
601
        }
602
#endif
603
 
604
        proc packages { str } {
605
                if { $::current_template != "" } {
606
                        set_template_data "$::current_template,packages" $str
607
                } elseif { $::current_target != "" } {
608
                        set_target_data "$::current_target,packages" $str
609
                } else {
610
                        ASSERT 0
611
                }
612
        }
613
 
614
        proc directory { dir } {
615
                set_package_data "$::current_package,dir" $dir
616
        }
617
 
618
        proc alias { str } {
619
                if { $::current_package != "" } {
620
                        set_package_data "$::current_package,alias" $str
621
                }
622
        }
623
 
624
        proc hardware { } {
625
                set_package_data "$::current_package,hardware" 1
626
        }
627
 
628
        proc description { str } { }
629
        proc disable { str } { }
630
        proc enable { str } { }
631
        proc script { str } { }
632
        proc set_value { str1 str2 } { }
633
        }
634
 
635
        # The parser is ready to evaluate the script. To avoid having to give the
636
        # safe interpreter file I/O capabilities, the file is actually read in
637
        # here and then evaluated.
638
        set filename [file join $ecosadmin::component_repository "ecos.db"]
639
        set status [ catch {
640
                set fd [open $filename r]
641
                set script [read $fd]
642
                close $fd
643
                $parser eval $script
644
} message ]
645
 
646
        if { $status != 0 } {
647
                ecosadmin::fatal_error "parsing $filename:\n$message"
648
        }
649
 
650
        # The interpreter and the aliased commands are no longer required.
651
        rename set_package_data {}
652
        rename set_target_data {}
653
        rename set_template_data {}
654
        rename add_known_package {}
655
        interp delete $parser
656
 
657
        # At this stage the packages file has been read in. It is a good idea to
658
        # check that all of these packages are present and correct, and incidentally
659
        # figure out which versions are present.
660
        foreach pkg $ecosadmin::known_packages {
661
 
662
                set pkgdir [file join $ecosadmin::component_repository $ecosadmin::package_data($pkg,dir)]
663
                if { ![file exists $pkgdir] || ![file isdir $pkgdir] } {
664
                        if { "" == $silentflag } {
665
                                warning "package $pkg at $pkgdir missing"
666
                        }
667
                } else {
668
                        # Each subdirectory should correspond to a release. A utility routine
669
                        # is available for this.
670
                        set ecosadmin::package_data($pkg,versions) [locate_subdirs $pkgdir]
671
                        if { $ecosadmin::package_data($pkg,versions) == "" } {
672
                                fatal_error "package $pkg has no version directories"
673
                        }
674
                }
675
                # Sort all the versions using a version-aware comparison version
676
                set ecosadmin::package_data($pkg,versions) [
677
                        lsort -command ecosadmin::cdl_compare_version $ecosadmin::package_data($pkg,versions)
678
                ]
679
        }
680
}
681
 
682
#
683
# Given a package name as supplied by the user, return the internal package name.
684
# This involves searching through the list of aliases.
685
#
686
proc ecosadmin::find_package { name } {
687
 
688
        foreach pkg $ecosadmin::known_packages {
689
                if { [string toupper $pkg] == [string toupper $name] } {
690
                        return $pkg
691
                }
692
 
693
                foreach alias $ecosadmin::package_data($pkg,alias) {
694
                        if { [string toupper $alias] == [string toupper $name] } {
695
                                return $pkg
696
                        }
697
                }
698
        }
699
 
700
        return ""
701
}
702
 
703
# }}}
704
# {{{  Directory and file utilities
705
 
706
# ----------------------------------------------------------------------------
707
# Start with a number of utility routines to access all files in
708
# a directory, stripping out well-known files such as makefile.am.
709
# The routines take an optional pattern argument if only certain
710
# files are of interest.
711
#
712
# Note that symbolic links are returned as well as files.
713
#
714
proc ecosadmin::locate_files { dir { pattern "*"} } {
715
 
716
        ASSERT { $dir != "" }
717
 
718
        # Start by getting a list of all the files.
719
        set filelist [glob -nocomplain -- [file join $dir $pattern]]
720
 
721
        if { $pattern == "*" } {
722
                # For "everything", include ".*" files, but excluding .
723
                # and .. directories
724
                lappend filelist [glob -nocomplain -- [file join $dir ".\[a-zA-Z0-9\]*"]]
725
        }
726
 
727
        # Eliminate the pathnames from all of these files
728
        set filenames ""
729
        foreach file $filelist {
730
                if { [string range $file end end] != "~" } {
731
                        lappend filenames [file tail $file]
732
                }
733
        }
734
 
735
        # Eliminate any subdirectories.
736
        set subdirs ""
737
        foreach name $filenames {
738
                if { [file isdir [file join $dir $name]] } {
739
                        lappend subdirs $name
740
                }
741
        }
742
        foreach subdir $subdirs {
743
                set index [lsearch -exact $filenames $subdir]
744
                set filenames [lreplace $filenames $index $index]
745
        }
746
 
747
        return $filenames
748
}
749
 
750
#
751
# This utility returns all sub-directories, as opposed to all files.
752
# A variant glob pattern is used here. This version is not recursive.
753
proc ecosadmin::locate_subdirs { dir { pattern "*" }} {
754
 
755
        ASSERT { $dir != "" }
756
 
757
        set dirlist [glob -nocomplain -- [file join $dir $pattern]]
758
 
759
        # Eliminate the pathnames and the regular (non-directory) files
760
        set dirnames ""
761
        foreach dir $dirlist {
762
                if { [file isdirectory $dir] } {
763
                        lappend dirnames [file tail $dir]
764
                }
765
        }
766
 
767
        # Get rid of the CVS directory, if any
768
        if { $ecosadmin::keep_cvs == 0 } {
769
                set index [lsearch -exact $dirnames "CVS"]
770
                if { $index != -1 } {
771
                        set dirnames [lreplace $dirnames $index $index]
772
                }
773
        }
774
 
775
        # That should be it.
776
        return $dirnames
777
}
778
 
779
#
780
# A variant which is recursive. This one does not support a pattern.
781
#
782
proc ecosadmin::locate_all_subdirs { dir } {
783
 
784
        ASSERT { $dir != "" }
785
 
786
        set result ""
787
        foreach subdir [locate_subdirs $dir] {
788
                lappend result $subdir
789
                foreach x [locate_all_subdirs [file join $dir $subdir]] {
790
                        lappend result [file join $subdir $x]
791
                }
792
        }
793
        return $result
794
}
795
 
796
#
797
# This routine returns a list of all the files in a given directory and in
798
# all subdirectories, preserving the subdirectory name.
799
#
800
proc ecosadmin::locate_all_files { dir { pattern "*" } } {
801
 
802
        ASSERT { $dir != "" }
803
 
804
        set files   [locate_files $dir $pattern]
805
        set subdirs [locate_subdirs $dir]
806
 
807
        foreach subdir $subdirs {
808
                set subfiles [locate_all_files [file join $dir $subdir] $pattern]
809
                foreach file $subfiles {
810
                        lappend files [file join $subdir $file]
811
                }
812
        }
813
 
814
        return $files
815
}
816
 
817
#
818
# Sometimes a directory may be empty, or contain just a CVS subdirectory,
819
# in which case there is no point in copying it across.
820
#
821
proc ecosadmin::is_empty_directory { dir } {
822
 
823
        ASSERT { $dir != "" }
824
 
825
        set contents [glob -nocomplain -- [file join $dir "*"]]
826
        if { [llength $contents] == 0 } {
827
                return 1
828
        }
829
        if { ([llength $contents] == 1) && [string match {*CVS} $contents] } {
830
                return 1
831
        }
832
        return 0
833
}
834
 
835
#
836
# ----------------------------------------------------------------------------
837
# Take a cygwin32 filename such as //d/tmp/pkgobj and turn it into something
838
# acceptable to Tcl, i.e. d:/tmp/pkgobj. There are a few other complications...
839
 
840
proc ecosadmin::get_pathname_for_tcl { name } {
841
 
842
        if { ( $ecosadmin::windows_host ) && ( $name != "" ) } {
843
 
844
                # If there is no logical drive letter specified
845
                if { [ string match "?:*" $name ] == 0 } {
846
 
847
                        # Invoke cygpath to resolve the POSIX-style path
848
                        if { [ catch { exec cygpath -w $name } result ] != 0 } {
849
                                fatal_error "processing filepath $name:\n$result"
850
                        }
851
                } else {
852
                        set result $name
853
                }
854
 
855
                # Convert backslashes to forward slashes
856
                regsub -all -- {\\} $result "/" name
857
        }
858
 
859
        return $name
860
}
861
 
862
# ----------------------------------------------------------------------------
863
# Make sure that a newly created or copied file is writable. This operation
864
# is platform-specific. Under Unix at most the current user is given
865
# permission, since there does not seem to be any easy way to get hold
866
# of the real umask.
867
 
868
proc ecosadmin::make_writable { name } {
869
 
870
        ASSERT { $name != "" }
871
        ASSERT { [file isfile $name] }
872
 
873
        if { [file writable $name] == 0 } {
874
                if { $ecosadmin::windows_host != 0 } {
875
                        file attributes $name -readonly 0
876
                } else {
877
                        set mask [file attributes $name -permissions]
878
                        set mask [expr $mask | 0200]
879
                        file attributes $name -permissions $mask
880
                }
881
        }
882
}
883
 
884
# }}}
885
# {{{  main()
886
 
887
#-----------------------------------------------------------------------
888
# Procedure target_requires_missing_package determines whether a
889
# target entry is dependent on missing packages. It is called when
890
# filtering templates out of the database
891
 
892
proc ecosadmin::target_requires_missing_package { target } {
893
        foreach package $ecosadmin::target_data($target,packages) {
894
                if { [ lsearch $ecosadmin::known_packages $package ] == -1 } {
895
                        return 1
896
                }
897
        }
898
        return 0
899
}
900
 
901
#-----------------------------------------------------------------------
902
# Procedure template_requires_missing_package determines whether a
903
# template entry is dependent on missing packages. It is called when
904
# filtering templates out of the database
905
 
906
proc ecosadmin::template_requires_missing_package { template } {
907
        foreach package $ecosadmin::template_data($template,packages) {
908
                if { [ lsearch $ecosadmin::known_packages $package ] == -1 } {
909
                        return 1
910
                }
911
        }
912
        return 0
913
}
914
 
915
#-----------------------------------------------------------------------
916
# Procedure target_requires_any_package determines whether a target entry
917
# is dependent on specified packages. It is called when removing packages
918
# to determine whether a target should also be removed
919
 
920
proc ecosadmin::target_requires_any_package { target packages } {
921
        foreach package $packages {
922
                if { [ lsearch $ecosadmin::target_data($target,packages) $package ] != -1 } {
923
                        return 1
924
                }
925
        }
926
        return 0
927
}
928
 
929
#-----------------------------------------------------------------------
930
# Procedure template_requires_any_package determines whether a template entry
931
# is dependent on specified packages. It is called when removing packages
932
# to determine whether a template should also be removed
933
 
934
proc ecosadmin::template_requires_any_package { template packages } {
935
        foreach package $packages {
936
                if { [ lsearch $ecosadmin::template_data($template,packages) $package ] != -1 } {
937
                        return 1
938
                }
939
        }
940
        return 0
941
}
942
 
943
#-----------------------------------------------------------------------
944
# Procedure merge_new_packages adds any entries in the specified data
945
# file to the eCos repository database iff they are not already present
946
 
947
proc ecosadmin::merge_new_packages { datafile } {
948
        # array of targets which require merging of package list
949
        array set ::ecosadmin::merge_target_packages {}
950
        variable ::ecosadmin::merge_targets ""
951
        variable ::ecosadmin::target_packages ""
952
 
953
        # open the eCos database file for appending
954
        set ecosfile [ file join $ecosadmin::component_repository "ecos.db" ]
955
        variable outfile [ open $ecosfile a+ ]
956
 
957
        # initialize the list of merged packages
958
        set ecosadmin::merge_packages ""
959
 
960
        # this procedure is called when the interpreter encounters a
961
        # package command in the datafile
962
        proc merge { command name body } {
963
                ecosadmin::report "processing $command $name"
964
                # append the new package/target/template only if it is not already known
965
                if { ( ( $command == "package" ) && ( [ lsearch -exact $ecosadmin::known_packages $name ] == -1 ) ) ||
966
                        ( ( $command == "target" ) && ( [ lsearch -exact $ecosadmin::known_targets $name ] == -1 ) ) ||
967
                        ( ( $command == "template" ) && ( [ lsearch -exact $ecosadmin::known_templates $name ] == -1 ) ) } {
968
                        puts $ecosadmin::outfile "$command $name {$body}\n"
969
                } elseif { ($command == "target") } {
970
                        # target is already defined so store any new package names for a possible merge
971
                        set merge_required 0
972
                        foreach pkg $ecosadmin::target_packages {
973
                                # for each package name in the target record
974
                                if { [ lsearch $ecosadmin::target_data($name,packages) $pkg ] == -1 } {
975
                                        # package name is not in the existing target record
976
                                        lappend ecosadmin::merge_target_packages($name) $pkg
977
                                        set merge_required 1
978
                                }
979
                        }
980
                        if { $merge_required == 1 } {
981
                                # at least one package name is not in the existing target record
982
                                lappend ecosadmin::merge_targets $name
983
                        }
984
                }
985
 
986
                # add new packages to the list of merged packages
987
                if { ( "package" == $command ) } {
988
                        lappend ecosadmin::merge_packages $name
989
                }
990
        }
991
 
992
        proc set_target_packages { packages } {
993
                set ecosadmin::target_packages $packages
994
        }
995
 
996
        # Create the parser, add the aliased commands, and then define
997
        # the routines that do the real work.
998
        set parser [ interp create -safe ]
999
        $parser alias merge ecosadmin::merge
1000
        $parser alias set_target_packages ecosadmin::set_target_packages
1001
        $parser eval {
1002
                proc package { name body } {
1003
                        merge "package" $name $body
1004
                }
1005
 
1006
                proc template { name body } {
1007
                        merge "template" $name $body
1008
                }
1009
 
1010
                proc target { name body } {
1011
                        eval $body
1012
                        merge "target" $name $body
1013
                }
1014
 
1015
                proc packages { str } {
1016
                        set_target_packages $str
1017
                }
1018
 
1019
                proc alias { str } { }
1020
                proc description { str } { }
1021
                proc disable { str } { }
1022
                proc enable { str } { }
1023
                proc set_value { str1 str2 } { }
1024
        }
1025
 
1026
        # The parser is ready to evaluate the script. To avoid having to give the
1027
        # safe interpreter file I/O capabilities, the file is actually read in
1028
        # here and then evaluated.
1029
        set status [ catch {
1030
                set fd [ open $datafile r ]
1031
                set script [ read $fd ]
1032
                close $fd
1033
                $parser eval $script
1034
        } message ]
1035
 
1036
        # The interpreter and the aliased commands are no longer required.
1037
        rename merge {}
1038
        rename set_target_packages {}
1039
        interp delete $parser
1040
 
1041
        # close the eCos database file
1042
        close $outfile
1043
 
1044
        # report errors
1045
        if { $status != 0 } {
1046
                ecosadmin::fatal_error "parsing $datafile:\n$message"
1047
        }
1048
 
1049
        # having appended any new records to ecos.db we can now merge extra
1050
        # packages into target records as necessary
1051
 
1052
        # open the new eCos database file for writing
1053
        set ecosfile [ file join $ecosadmin::component_repository "ecos.db.new" ]
1054
        variable outfile [ open $ecosfile w ]
1055
        variable target_packages ""
1056
        variable target_attributes ""
1057
 
1058
        # this procedure is called when the interpreter encounters a command in ecos.db when
1059
        # merging extra packages into target records
1060
        proc merge_target { command name body } {
1061
                if { ( $command == "target" ) && ( [ lsearch $ecosadmin::merge_targets $name ] != -1 ) } {
1062
                        # add new package(s) to the target definition
1063
                        puts $ecosadmin::outfile "$command $name \{\n$ecosadmin::target_attributes \tpackages \{"
1064
                        foreach pkg $ecosadmin::target_packages {
1065
                                puts $ecosadmin::outfile "\t\t$pkg"
1066
                        }
1067
                        foreach pkg $ecosadmin::merge_target_packages($name) {
1068
                                ecosadmin::report "adding $pkg to target $name"
1069
                                puts $ecosadmin::outfile "\t\t$pkg"
1070
                        }
1071
                        puts $ecosadmin::outfile "\t\}\n\}\n"
1072
                } else {
1073
                        # copy the data record to the new database
1074
                        puts $ecosadmin::outfile "$command $name {$body}\n"
1075
                }
1076
        }
1077
 
1078
        proc add_target_attribute { attribute value } {
1079
                set ecosadmin::target_attributes "$ecosadmin::target_attributes \t$attribute $value\n"
1080
        }
1081
 
1082
        proc clear_target_attributes { } {
1083
                set ecosadmin::target_attributes ""
1084
        }
1085
 
1086
        proc set_target_packages { packages } {
1087
                set ecosadmin::target_packages $packages
1088
        }
1089
 
1090
        # Create the parser, add the aliased commands, and then define
1091
        # the routines that do the real work.
1092
        set parser [ interp create -safe ]
1093
        $parser alias add_target_attribute ecosadmin::add_target_attribute
1094
        $parser alias set_target_packages ecosadmin::set_target_packages
1095
        $parser alias clear_target_attributes ecosadmin::clear_target_attributes
1096
        $parser eval {
1097
                proc package { name body } {
1098
                        filter "package" $name $body
1099
                }
1100
 
1101
                proc template { name body } {
1102
                        filter "template" $name $body
1103
                }
1104
 
1105
                proc target { name body } {
1106
                        clear_target_attributes
1107
                        eval $body
1108
                        filter "target" $name $body
1109
                }
1110
 
1111
                proc packages { str } {
1112
                        set_target_packages $str
1113
                }
1114
 
1115
                proc alias { str } {
1116
                        add_target_attribute "alias" \{$str\}
1117
                }
1118
 
1119
                proc description { str } {
1120
                        add_target_attribute "description" \"$str\"
1121
                }
1122
 
1123
                proc disable { str } {
1124
                        add_target_attribute "disable" \{$str\}
1125
                }
1126
 
1127
                proc enable { str } {
1128
                        add_target_attribute "enable" \{$str\}
1129
                }
1130
 
1131
                proc set_value { str1 str2 } {
1132
                        add_target_attribute "set_value" "$str1 \"$str2\""
1133
                }
1134
        }
1135
 
1136
        # The parser is ready to evaluate the script. To avoid having to give the
1137
        # safe interpreter file I/O capabilities, the file is actually read in
1138
        # here and then evaluated.
1139
        set filename [ file join $ecosadmin::component_repository "ecos.db" ]
1140
        set status [ catch {
1141
                set fd [ open $filename r ]
1142
                set script [ read $fd ]
1143
                close $fd
1144
 
1145
                $parser alias filter ecosadmin::merge_target
1146
                $parser eval $script
1147
        } message ]
1148
 
1149
        # The interpreter and the aliased commands are no longer required.
1150
        rename merge_target {}
1151
        interp delete $parser
1152
 
1153
        # close the new eCos database file
1154
        close $outfile
1155
 
1156
        # report errors
1157
        if { $status != 0 } {
1158
                ecosadmin::fatal_error "parsing $filename:\n$message"
1159
        }
1160
 
1161
        # replace the old eCos database file with the new one
1162
        file rename -force $ecosfile $filename
1163
}
1164
 
1165
#-----------------------------------------------------------------------
1166
# Procedure filter_old_packages removes the specified packages/versions
1167
# from the eCos repository database. Any targets and templates dependent
1168
# on the removed packages are also removed.
1169
 
1170
proc ecosadmin::filter_old_packages { old_packages } {
1171
 
1172
        # open the new eCos database file for writing
1173
        set ecosfile [ file join $ecosadmin::component_repository "ecos.db.new" ]
1174
        variable outfile [ open $ecosfile w ]
1175
        variable filter_list $old_packages
1176
        variable removed_packages ""
1177
        variable target_packages ""
1178
        variable target_attributes ""
1179
 
1180
        # this procedure is called when the interpreter encounters a command in the datafile on the first pass
1181
        # it generates a list of packages which will be removed on the second pass
1182
        proc removelist { command name body } {
1183
                if { [ lsearch $ecosadmin::filter_list $name ] != -1 } {
1184
                        # the package is in the filter list
1185
                        if { ( $ecosadmin::version_arg == "" ) || ( [ llength $ecosadmin::package_data($name,versions) ] == 1 ) } {
1186
                                # there is no version argument or only one version so add the package to the remove list
1187
                                set ::ecosadmin::removed_packages [ lappend ::ecosadmin::removed_packages $name ]
1188
                        }
1189
                }
1190
        }
1191
 
1192
        # this procedure is called when the interpreter encounters a command in the datafile on the second pass
1193
        proc filter { command name body } {
1194
                if { ( $command == "target" ) && ( ( [ target_requires_any_package $name $ecosadmin::removed_packages ] != 0 ) || ( [ target_requires_missing_package $name ] != 0 ) ) } {
1195
                        # the target requires a package which has been removed
1196
                        if { $ecosadmin::keep_targets_arg != 1 } {
1197
                                # "--remove_targets" specified so remove the target
1198
                                ecosadmin::report "removing target $name"
1199
                        } else {
1200
                                # remove missing packages from the target definition
1201
                                puts $ecosadmin::outfile "$command $name \{\n$ecosadmin::target_attributes \tpackages \{"
1202
                                foreach pkg $ecosadmin::target_packages {
1203
                                        if { ([ lsearch $ecosadmin::removed_packages $pkg ] == -1) && ([ lsearch $ecosadmin::known_packages $pkg ] != -1) } {
1204
                                                # package exists and has not been listed for removal so keep it in the target definition
1205
                                                puts $ecosadmin::outfile "\t\t$pkg"
1206
                                        } else {
1207
                                                # package is missing or has been listed for removal so remove it from the target definition
1208
                                                puts "removing $pkg from $name target record"
1209
                                        }
1210
                                }
1211
                                puts $ecosadmin::outfile "\t\}\n\}\n"
1212
                        }
1213
                } elseif { ( $command == "template" ) && ( ( [ template_requires_any_package $name $ecosadmin::removed_packages ] != 0 ) || ( [ template_requires_missing_package $name ] != 0 ) ) } {
1214
                        # the template requires a package which has been removed so remove the template
1215
                        ecosadmin::report "removing template $name"
1216
                } elseif { [ lsearch $ecosadmin::filter_list $name ] == -1 } {
1217
                        # the package is not in the filter list so copy the data to the new database
1218
                        puts $ecosadmin::outfile "$command $name {$body}\n"
1219
                } else {
1220
                        # the package is in the filter list
1221
                        set package_dir [ file join $ecosadmin::component_repository $ecosadmin::package_data($name,dir) ]
1222
                        if { ( $ecosadmin::version_arg != "" ) && ( [ llength $ecosadmin::package_data($name,versions) ] > 1 ) } {
1223
                                # there are multiple versions and only one version will be removed
1224
                                # so copy the data to the new database and only remove one version directory
1225
                                set package_dir [ file join $package_dir $ecosadmin::version_arg ]
1226
                                ecosadmin::report "removing package $name $ecosadmin::version_arg"
1227
                                puts $ecosadmin::outfile "$command $name {$body}\n"
1228
                        } else {
1229
                                # there is no version argument or only one version so delete the package directory
1230
                                ecosadmin::report "removing package $name"
1231
                        }
1232
                        if { [ catch { file delete -force -- $package_dir } message ] != 0 } {
1233
                                # issue a warning if package deletion failed - this is not fatal
1234
                                ecosadmin::warning $message
1235
                        }
1236
                        set dir [ file dirname $package_dir ]
1237
                        while { [ llength [ glob -nocomplain -- [ file join $dir "*" ] ] ] == 0 } {
1238
                                # the parent of the deleted directory is now empty so delete it
1239
                                if { [ catch { file delete -- $dir } message ] != 0 } {
1240
                                        # issue a warning if empty directory deletion failed - this is not fatal
1241
                                        ecosadmin::warning $message
1242
                                }
1243
                                set dir [ file dirname $dir ]
1244
                        }
1245
                }
1246
        }
1247
 
1248
        proc add_target_attribute { attribute value } {
1249
                set ecosadmin::target_attributes "$ecosadmin::target_attributes \t$attribute $value\n"
1250
        }
1251
 
1252
        proc clear_target_attributes { } {
1253
                set ecosadmin::target_attributes ""
1254
        }
1255
 
1256
        proc set_target_packages { packages } {
1257
                set ecosadmin::target_packages $packages
1258
        }
1259
 
1260
        # Create the parser, add the aliased commands, and then define
1261
        # the routines that do the real work.
1262
        set parser [ interp create -safe ]
1263
        $parser alias add_target_attribute ecosadmin::add_target_attribute
1264
        $parser alias set_target_packages ecosadmin::set_target_packages
1265
        $parser alias clear_target_attributes ecosadmin::clear_target_attributes
1266
        $parser eval {
1267
                proc package { name body } {
1268
                        filter "package" $name $body
1269
                }
1270
 
1271
                proc template { name body } {
1272
                        filter "template" $name $body
1273
                }
1274
 
1275
                proc target { name body } {
1276
                        clear_target_attributes
1277
                        eval $body
1278
                        filter "target" $name $body
1279
                }
1280
 
1281
                proc packages { str } {
1282
                        set_target_packages $str
1283
                }
1284
 
1285
                proc alias { str } {
1286
                        add_target_attribute "alias" \{$str\}
1287
                }
1288
 
1289
                proc description { str } {
1290
                        add_target_attribute "description" \"$str\"
1291
                }
1292
 
1293
                proc disable { str } {
1294
                        add_target_attribute "disable" \{$str\}
1295
                }
1296
 
1297
                proc enable { str } {
1298
                        add_target_attribute "enable" \{$str\}
1299
                }
1300
 
1301
                proc set_value { str1 str2 } {
1302
                        add_target_attribute "set_value" "$str1 \"$str2\""
1303
                }
1304
        }
1305
 
1306
        # The parser is ready to evaluate the script. To avoid having to give the
1307
        # safe interpreter file I/O capabilities, the file is actually read in
1308
        # here and then evaluated.
1309
        set filename [ file join $ecosadmin::component_repository "ecos.db" ]
1310
        set status [ catch {
1311
                set fd [ open $filename r ]
1312
                set script [ read $fd ]
1313
                close $fd
1314
 
1315
                # first pass to generate a list of packages which will be removed
1316
                $parser alias filter ecosadmin::removelist
1317
                $parser eval $script
1318
 
1319
                # second pass to remove the packages, targets and templates
1320
                $parser alias filter ecosadmin::filter
1321
                $parser eval $script
1322
        } message ]
1323
 
1324
        # The interpreter and the aliased commands are no longer required.
1325
        rename filter {}
1326
        interp delete $parser
1327
 
1328
        # close the new eCos database file
1329
        close $outfile
1330
 
1331
        # report errors
1332
        if { $status != 0 } {
1333
                ecosadmin::fatal_error "parsing $filename:\n$message"
1334
        }
1335
 
1336
        # replace the old eCos database file with the new one
1337
        file rename -force $ecosfile $filename
1338
}
1339
 
1340
# ----------------------------------------------------------------------------
1341
# Process_add_packages. This routine is responsible for installing packages
1342
# into the eCos repository using the gzip and tar tools which must be on
1343
# the path
1344
#
1345
 
1346
proc ecosadmin::process_add_package { } {
1347
        ASSERT { $ecosadmin::add_package != "" }
1348
        ASSERT { $ecosadmin::component_repository != "" }
1349
 
1350
        # calculate the absolute path of the specified package archive
1351
        # since we must change directory before extracting files
1352
        # note that we cannot use "tar -C" to avoid changing directory
1353
        # since "tar -C" only accepts relative paths
1354
        set abs_package [ file join [ pwd ] $ecosadmin::add_package ]
1355
        set datafile "pkgadd.db"
1356
        set licensefile "pkgadd.txt"
1357
        set logfile "pkgadd.log"
1358
        cd $ecosadmin::component_repository
1359
 
1360
        # check for --extract_license on command line
1361
        if { $ecosadmin::extract_license_arg == 1 } {
1362
                # extract the license file (if any) from the specified gzipped tar archive
1363
                file delete $licensefile
1364
                catch { exec > $ecosadmin::null_device gzip -d < $abs_package | tar xf - $licensefile }
1365
                return
1366
        }
1367
 
1368
        # extract the package data file from the specified gzipped tar archive
1369
        if { [ catch { exec > $ecosadmin::null_device gzip -d < $abs_package | tar xf - $datafile } message ] != 0 } {
1370
                fatal_error "extracting $datafile:\n$message"
1371
        }
1372
 
1373
        # obtain license acceptance
1374
        if { [ ecosadmin::accept_license $abs_package $licensefile ] != "y" } {
1375
                file delete $datafile
1376
                file delete $licensefile
1377
                fatal_error "license agreement not accepted"
1378
        }
1379
 
1380
        # extract the remaining package contents and generate a list of extracted files
1381
        if { [ catch { exec gzip -d < $abs_package | tar xvf - > $logfile } message ] != 0 } {
1382
                file delete $logfile
1383
                fatal_error "extracting files:\n$message"
1384
        }
1385
 
1386
        # read the list of extracted files from the log file
1387
        set fd [ open $logfile r ]
1388
        set message [ read $fd ]
1389
        close $fd
1390
        file delete $logfile
1391
 
1392
        # convert extracted text files to use the line-ending convention of the host
1393
        set filelist [ split $message "\n" ]
1394
        set binary_extension ".bin"
1395
        foreach filename $filelist {
1396
                if { [ file isfile $filename ] != 0 } {
1397
                        if { [ file extension $filename ] == $binary_extension } {
1398
                                # a binary file - so remove the binary extension
1399
                                file rename -force -- $filename [ file rootname $filename ]
1400
                        } else {
1401
                                # a text file - so convert file to use native line-endings
1402
                                # read in the file (line-ending conversion is implicit)
1403
                                set fd [ open $filename "r" ]
1404
                                set filetext [ read $fd ]
1405
                                close $fd
1406
 
1407
                                # write the file out again
1408
                                set fd [ open $filename "w" ]
1409
                                puts -nonewline $fd $filetext
1410
                                close $fd
1411
                        }
1412
                }
1413
        }
1414
 
1415
        # merge the new package information into the eCos database file as necessary
1416
        ecosadmin::merge_new_packages [ file join $ecosadmin::component_repository $datafile ]
1417
 
1418
        # delete the database and license files
1419
        file delete $datafile
1420
        file delete $licensefile
1421
 
1422
        # read the revised database back in and remove any
1423
        # targets and templates with missing packages
1424
        read_data ""
1425
        filter_old_packages ""
1426
}
1427
 
1428
# ----------------------------------------------------------------------------
1429
# Process_remove_package. This routine is responsible for uninstalling a
1430
# package from the eCos repository
1431
#
1432
 
1433
proc ecosadmin::process_remove_package { } {
1434
        ASSERT { $ecosadmin::remove_package != "" }
1435
 
1436
        # get the formal package name
1437
        set package_name [ ecosadmin::find_package $ecosadmin::remove_package ]
1438
        if { $package_name == "" } {
1439
                # package not found
1440
                fatal_error "package $ecosadmin::remove_package not found"
1441
        } elseif { $ecosadmin::version_arg == "" } {
1442
                # version not specified
1443
#               if { [ llength $ecosadmin::package_data($package_name,versions) ] > 1 } {
1444
#                       fatal_error "multiple versions, use --version"
1445
#               }
1446
        } elseif { [ lsearch $ecosadmin::package_data($package_name,versions) $ecosadmin::version_arg ] == -1 } {
1447
                # specified version not found
1448
                fatal_error "version $ecosadmin::version_arg not found"
1449
        }
1450
 
1451
        # filter out the old package from the eCos database file
1452
        filter_old_packages $package_name
1453
}
1454
 
1455
# ----------------------------------------------------------------------------
1456
# Process_clean_database. This routine is responsible for tidying up an
1457
# eCos repository package database
1458
#
1459
 
1460
proc ecosadmin::process_clean_database { } {
1461
 
1462
        # filter out missing packages from the eCos database file
1463
        filter_old_packages ""
1464
}
1465
 
1466
# ----------------------------------------------------------------------------
1467
# Process_check_database. This routine is responsible for checking an
1468
# eCos repository package database
1469
#
1470
 
1471
proc ecosadmin::process_check_database { } {
1472
 
1473
        foreach target $ecosadmin::known_targets {
1474
                foreach package $ecosadmin::target_data($target,packages) {
1475
                        if { [ lsearch -exact $ecosadmin::known_packages $package ] != -1 } {
1476
                                if { $ecosadmin::package_data($package,hardware) != 1 } {
1477
                                        ecosadmin::warning "non-hardware package $package used in target $target"
1478
                                }
1479
                        } else {
1480
                                ecosadmin::warning "target $target refers to non-existent package $package"
1481
                        }
1482
                }
1483
        }
1484
        foreach package $ecosadmin::known_packages {
1485
                if { $ecosadmin::package_data($package,hardware) == 1 } {
1486
                        variable hardware_package_required 0
1487
                        foreach target $ecosadmin::known_targets {
1488
                                if { [ target_requires_any_package $target $package ] } {
1489
                                        set hardware_package_required 1
1490
                                }
1491
                        }
1492
                        if { $hardware_package_required == 0 } {
1493
                                ecosadmin::warning "hardware package $package not used by any target"
1494
                        }
1495
                }
1496
        }
1497
}
1498
 
1499
# ----------------------------------------------------------------------------
1500
# Process_merge_repository. This routine is responsible for merging packages
1501
# from another repository into the eCos repository
1502
#
1503
 
1504
proc ecosadmin::process_merge_repository { } {
1505
        ASSERT { $ecosadmin::merge_repository != "" }
1506
        ASSERT { $ecosadmin::component_repository != "" }
1507
 
1508
        # merge new package and target information into the eCos database file as necessary
1509
        # names of packages to be merged are placed in $ecosadmin::merge_packages
1510
        ecosadmin::merge_new_packages [ file join $ecosadmin::merge_repository "ecos.db" ]
1511
 
1512
        # read the revised database back in to pick up new package paths, but ignore missing package directories
1513
        read_data "silent"
1514
 
1515
        # copy package directories into the repository as necessary
1516
        # existing packages are never replaced but a another version may be added
1517
        foreach pkg $ecosadmin::merge_packages {
1518
                set newpkgdir [file join $ecosadmin::merge_repository $ecosadmin::package_data($pkg,dir)]
1519
                foreach newpkgver [locate_subdirs $newpkgdir] {
1520
                        if { [lsearch $ecosadmin::package_data($pkg,versions) $newpkgver] == -1 } {
1521
                                ecosadmin::report "copying $pkg $newpkgver"
1522
                                file mkdir [ file join $ecosadmin::component_repository $ecosadmin::package_data($pkg,dir) ]
1523
                                file copy [ file join $newpkgdir $newpkgver ] [ file join $ecosadmin::component_repository $ecosadmin::package_data($pkg,dir) $newpkgver ]
1524
                        }
1525
                }
1526
        }
1527
 
1528
        # read the revised database again to deliver warnings of missing package directories if necessary
1529
        read_data ""
1530
 
1531
        # copy new files from the pkgconf and templates directory hierarchies into the repository as necessary
1532
        foreach topdir { pkgconf templates } {
1533
                set repository_files [ ecosadmin::locate_all_files [ file join $ecosadmin::component_repository $topdir ] ]
1534
                set merge_files [ ecosadmin::locate_all_files [ file join $ecosadmin::merge_repository $topdir ] ]
1535
                foreach filename $merge_files {
1536
                        if { [string length $filename] > 0 && [lsearch $repository_files $filename] == -1 } {
1537
                                ecosadmin::report "copying $topdir file $filename"
1538
                                file mkdir [ file join $ecosadmin::component_repository $topdir [ file dirname $filename ] ]
1539
                                file copy [ file join $ecosadmin::merge_repository $topdir $filename ] [ file join $ecosadmin::component_repository $topdir $filename ]
1540
                        }
1541
                }
1542
        }
1543
 
1544
        # copy files from the top level packages directory into the repository as necessary
1545
        foreach filename [ glob -nocomplain -directory $ecosadmin::merge_repository -type f * ] {
1546
                set destination [ file join $ecosadmin::component_repository [ file tail $filename ] ]
1547
                if { 0 == [ file exists $destination ] } {
1548
                        ecosadmin::report "copying file [file tail $filename]"
1549
                        file copy $filename $destination
1550
                }
1551
        }
1552
}
1553
 
1554
# ----------------------------------------------------------------------------
1555
# Accept_license. This routine is responsible for displaying the package
1556
# license and obtaining user acceptance. It returns "y" if the license is
1557
# accepted.
1558
#
1559
 
1560
proc ecosadmin::accept_license { archivename filename } {
1561
        ASSERT { $ecosadmin::add_package != "" }
1562
 
1563
        # check for --accept_license on command line
1564
        if { $ecosadmin::accept_license_arg == 1 } {
1565
                # --accept_license specified so do not prompt for acceptance
1566
                return "y"
1567
        }
1568
 
1569
        # extract the specified license file from the specified gzipped tar archive
1570
        if { [ catch { exec > $ecosadmin::null_device gzip -d < $archivename | tar xf - $filename } message ] != 0 } {
1571
                # no license file
1572
                return "y"
1573
        }
1574
 
1575
        # read in the file and output to the user
1576
        set fd [ open $filename "r" ]
1577
        set filetext [ read $fd ]
1578
        close $fd
1579
        puts $filetext
1580
 
1581
        # prompt for acceptance
1582
        puts -nonewline "Do you accept all the terms of the preceding license agreement? (y/n) "
1583
        flush "stdout"
1584
        gets "stdin" response
1585
 
1586
        # return the first character of the response in lowercase
1587
        return [ string tolower [ string index $response 0 ] ]
1588
}
1589
 
1590
# ----------------------------------------------------------------------------
1591
# Main(). This code only runs if the script is being run stand-alone rather
1592
# than as part of a larger application. The controlling predicate is the
1593
# existence of the variable ecosadmin_not_standalone which can be set by
1594
# the containing program if any.
1595
#
1596
 
1597
if { ! [info exists ecosadmin_not_standalone] } {
1598
 
1599
        # Decide where warnings and fatal errors should go.
1600
        ecosadmin::initialise_error_handling
1601
 
1602
        # First, check for --help or any of the variants. If this script
1603
        # is running in a larger program then it is assumed that the
1604
        # containing program will not pass --help as an argument.
1605
        if { ( $argv == "--help" ) || ( $argv == "-help" ) ||
1606
             ( $argv == "--H"    ) || ( $argv == "-H" ) || ($argv == "" ) } {
1607
 
1608
                ecosadmin::argument_help
1609
                return
1610
        }
1611
 
1612
        # catch any errors while processing the specified command
1613
        if { [ catch {
1614
 
1615
                # Parse the arguments and set the global variables appropriately.
1616
                ecosadmin::parse_arguments $argv0 $argv
1617
 
1618
                # Read in the eCos repository database.
1619
                ecosadmin::read_data ""
1620
 
1621
                # Process the ecosadmin command
1622
                if { $ecosadmin::list_packages_arg != 0 } {
1623
                        foreach pkg $ecosadmin::known_packages {
1624
                                ecosadmin::report "$pkg: $ecosadmin::package_data($pkg,versions)"
1625
                        }
1626
                } elseif { $ecosadmin::add_package != "" } {
1627
                        ecosadmin::process_add_package
1628
                } elseif { $ecosadmin::remove_package != "" } {
1629
                        ecosadmin::process_remove_package
1630
                } elseif { $ecosadmin::merge_repository != "" } {
1631
                        ecosadmin::process_merge_repository
1632
                } elseif { $ecosadmin::clean_database_arg != 0 } {
1633
                        ecosadmin::process_clean_database
1634
                } elseif { $ecosadmin::check_database_arg != 0 } {
1635
                        ecosadmin::process_check_database
1636
                }
1637
 
1638
        } error_message ] != 0 } {
1639
 
1640
                # handle error message
1641
                if { [ info exists gui_mode ] } {
1642
                        return $error_message
1643
                }
1644
                puts "ecosadmin error: $error_message"
1645
        }
1646
        return
1647
}
1648
 
1649
# }}}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.