#!/bin/sh #-*-tcl-*- # # aegis - project change supervisor # Copyright (C) 1999-2002, 2006-2008 Peter Miller # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # . # # @configure_input@ # # comments wrap in Tcl, but not in sh \ exec wish $0 ${1+"$@"} set bindir @bindir@ set libdir @libdir@ set datadir @datadir@ set datarootdir @datarootdir@ wm title . Aenc wm iconname . Aenc wm iconbitmap . @$datadir/aegis.icon wm iconmask . @$datadir/aegis.mask proc inform { arg } { .info.blurb insert end $arg .info.blurb see end .info.blurb insert end "\n" update } proc read_pipe { command errok } { set data "" set fd [open $command r] if { $fd != "" } { set data [read $fd] set codevar "" catch { close $fd } codevar if { $codevar != "" && !$errok } { inform [format "Command \"%s\"\nreturned \"%s\"" $command $codevar] } } return [string trim $data] } proc read_file { filename } { set data "" set fd [open $filename] if { $fd != "" } { set data [read $fd] set codevar "" catch { close $fd } codevar if { $codevar != "" } { inform [format "file %s error %s\"" $filename $codevar] } } return [string trim $data] } proc command_option_menu { w varName cmd firstValue args } { upvar #0 $varName var if {![info exists var]} { set var $firstValue } menubutton $w \ -textvariable $varName \ -indicatoron 1 \ -menu $w.menu \ -relief raised \ -bd 2 \ -highlightthickness 2 \ -anchor c \ -direction flush menu $w.menu -tearoff 0 $w.menu add radiobutton -label $firstValue -variable $varName foreach i $args { $w.menu add radiobutton -label $i -variable $varName \ -command $cmd } return $w.menu } proc project_drop_list { } { global project_name global project_list set x [winfo rootx .id.project.button] set y [winfo rooty .id.project.button] catch { destroy .popup } errcode toplevel .popup wm overrideredirect .popup 1 wm geometry .popup +$x+$y listbox .popup.list -height 12 -selectmode single \ -yscrollcommand ".popup.scroll set" set pos -1 foreach pn $project_list { if { $pn == $project_name } { set pos [.popup.list size] } .popup.list insert end $pn } if { $pos >= 0 } { .popup.list selection set $pos .popup.list see $pos } scrollbar .popup.scroll -command ".popup.list yview" pack .popup.scroll -side right -fill y pack .popup.list -side left bind .popup.list { set item [.popup.list curselection] if { $item != "" } { set item [.popup.list get $item] } if { $item != "" } { set project_name $item project_name_changed } destroy .popup } } proc developer_drop_list { } { global developer_name developer_full_name global developer_list developer_fullname_list set x [winfo rootx .bottom.right.developer.button] set y [winfo rooty .bottom.right.developer.button] catch { destroy .popup } errcode toplevel .popup wm overrideredirect .popup 1 wm geometry .popup +$x+$y listbox .popup.list -height 12 -selectmode single \ -yscrollcommand ".popup.scroll set" set pos -1 set count 0 foreach dev $developer_list { if { $dev == $developer_name } { set pos [.popup.list size] } # now get the index and insert the full name # (from the other list) .popup.list insert end [lindex $developer_fullname_list $count] incr count } if { $pos >= 0 } { .popup.list selection set $pos .popup.list see $pos } scrollbar .popup.scroll -command ".popup.list yview" pack .popup.scroll -side right -fill y pack .popup.list -side left bind .popup.list { set item [.popup.list curselection] if { $item != "" } { set new_dev [lindex $developer_list $item] } if { $new_dev != "" } { set developer_name $new_dev set developer_full_name [lindex $developer_fullname_list $item] } destroy .popup } } proc cause_changed { } { global cause global test_nor global test_bas global test_reg global proj_default_test_required # # Track the code in aegis/aenc.c::cattr_defaults() # if { $cause == "internal_improvement" || \ $cause == "external_improvement" } \ then { set test_nor 0 set test_bas 0 set test_reg 1 } else { set test_nor $proj_default_test_required set test_bas $proj_default_test_required set test_reg 0 } } proc update_developer_list { } { global who_am_i global developer_fullname_list global developer_list global developer_name global developer_full_name global datadir global project_name # # Ask Aegis for the list of developers. We use a specialized report # script which emits TCL code to set the developer_fullname_list # & developer_list variables. # inform "Reading list of developers..." eval [read_pipe [format \ "|aereport -f %s/wish/devs_list.rpt -project %s -unf -pw=1000" \ $datadir $project_name] 0] inform " ...done" # # Set the developer_name variable. The default is us, if we are a developer, # otherwise the first on the list. # inform "Reading default developer..." # Already done... inform " ...done" set developer_name $who_am_i set developer_list_empty [expr { [llength $developer_list] == 0 }] set dev_list_index [lsearch -exact $developer_list $who_am_i] if { $dev_list_index == -1 } { if { $developer_list_empty } { set developer_full_name "No Devlopers" set developer_name "" set developer_list_empty 1 } else { set developer_name [lindex $developer_list 0] } } if { !$developer_list_empty } { set developer_full_name \ [lindex $developer_fullname_list $dev_list_index] } } proc project_name_changed { } { global project_name global datadir global proj_brief_description global proj_description global proj_developer_may_review global proj_developer_may_integrate global proj_reviewer_may_integrate global proj_developers_may_create_changes global proj_umask global proj_minimum_change_number global proj_reuse_change_numbers global proj_minimum_branch_number global proj_skip_unlucky global proj_compress_database global proj_default_test_required global i_am_admin # # Ask Aegis for the project attributes # inform [format "Reading project %s attributes..." $project_name] eval [read_pipe [format \ "|aereport -f %s/wish/proj_attr.rpt -unf -pw=1000 -project=%s" \ $datadir $project_name ] 0] inform " ...done" # # Have the testing buttons track the project testing defaults. # cause_changed # # Update the list of developers details for this project # update_developer_list set previous_admin_status $i_am_admin determine_admin_status if { $i_am_admin && !$previous_admin_status } { # I have now become an admin, so need to create the extra admin # interface bits create_admin_if_extras } if { !$i_am_admin && $previous_admin_status } { # I was an admin, so need to destroy the extra admin # interface bits destroy_admin_if_extras } # if not an admin, no way to change test exemptions if {$i_am_admin} { set state normal } else { set state disabled } foreach btn {normal baseline regression} { .bottom.tests.$btn configure -state $state } } proc create_admin_if_extras { } { global start frame .bottom.right.developer -relief ridge -borderwidth 2 label .bottom.right.developer.label -text "Developer:" pack .bottom.right.developer.label -side top -anchor w button .bottom.right.developer.button -textvariable developer_full_name \ -command developer_drop_list pack .bottom.right.developer.button -side top -anchor nw -pady 5 -padx 5 pack .bottom.right.developer -side top -anchor nw -pady 5 -padx 5 if { $start == "later" } { disable_developer_button } else { enable_developer_button } wm title . "Aenc - Administrator" wm iconname . "Aenc - Administrator" } proc destroy_admin_if_extras { } { destroy .bottom.right.developer.label destroy .bottom.right.developer.button destroy .bottom.right.developer pack .bottom.right wm title . "Aenc" wm iconname . "Aenc" } proc determine_admin_status { } { global i_am_admin global who_am_i global project_name # # Am I an administrator? Basically used to determine if the developer # selection button is available. # if { $project_name != "" } { set proj_arg "-project $project_name" } else { set proj_arg "" } set admin_list [read_pipe \ [format "|aegis -list Administrators -unf %s" $proj_arg] 1] set i_am_admin [expr { [lsearch -exact $admin_list $who_am_i] != -1 }] } proc disable_developer_button { } { global i_am_admin # if the button exists then disable it. if { [winfo exists .bottom.right.developer.button] } { .bottom.right.developer.button configure -state disabled } } proc enable_developer_button { } { global i_am_admin # if the button exists then enable it. if { [winfo exists .bottom.right.developer.button] } { .bottom.right.developer.button configure -state active } } # and begin... set project_name "" set i_am_admin 0 set who_am_i "" # # Create the widget heirarchy first so the user has something to look at # while we fetch the remaining necessary information. # frame .id frame .id.project label .id.project.label -text "Project:" pack .id.project.label -side left button .id.project.button -textvariable project_name -command project_drop_list pack .id.project.button -side left pack .id.project -side left pack .id -side top -anchor w -pady 5 frame .bdesc label .bdesc.label -text "Brief Description:" pack .bdesc.label -side top -anchor w text .bdesc.text -height 1 pack .bdesc.text -side bottom -fill x pack .bdesc -fill x frame .desc label .desc.label -text "Description:" pack .desc.label -side top -anchor w text .desc.text -height 8 -yscrollcommand ".desc.scroll set" -wrap word \ -spacing3 5 scrollbar .desc.scroll -command ".desc.text yview" pack .desc.scroll -side right -fill y pack .desc.text -side bottom -fill both -expand 1 pack .desc -fill both -expand 1 frame .bottom set test_nor 1 set test_bas 1 set test_reg 1 frame .bottom.tests -relief ridge -width 100 -borderwidth 2 label .bottom.tests.label -text "Testing Required:" pack .bottom.tests.label -side top -anchor w checkbutton .bottom.tests.normal -text "Normal (Positive)" -variable test_nor \ -onvalue 1 -offvalue 0 pack .bottom.tests.normal -side top -anchor w checkbutton .bottom.tests.baseline -text "Baseline (Negative)" \ -variable test_bas -onvalue 1 -offvalue 0 pack .bottom.tests.baseline -side top -anchor w checkbutton .bottom.tests.regression -text "Regression" -variable test_reg \ -onvalue 1 -offvalue 0 pack .bottom.tests.regression -side top -anchor w pack .bottom.tests -side left -padx 5 -pady 5 -anchor nw frame .bottom.control button .bottom.control.ok -text "OK" -bg "#BFD0BF" -command "do_it" pack .bottom.control.ok -fill x button .bottom.control.cancel -text "Cancel" -command { exit 1 } -bg "#D0BFBF" pack .bottom.control.cancel -fill x -pady 5 pack .bottom.control pack .bottom.control -side right -padx 5 frame .bottom.cause -relief ridge -borderwidth 2 label .bottom.cause.label -text "Cause:" pack .bottom.cause.label -side top -anchor w radiobutton .bottom.cause.intbug -text "Internal Bug" -value "internal_bug" \ -variable cause -anchor w -command cause_changed pack .bottom.cause.intbug -side top -anchor w radiobutton .bottom.cause.intenh -text "Internal Enhancement" \ -value "internal_enhancement" -variable cause -anchor w \ -command cause_changed pack .bottom.cause.intenh -side top -anchor w radiobutton .bottom.cause.intimp -text "Internal Improvement" \ -value "internal_improvement" -variable cause -anchor w \ -command cause_changed pack .bottom.cause.intimp -side top -anchor w radiobutton .bottom.cause.extbug -text "External Bug" -value "external_bug" \ -variable cause -anchor w -command cause_changed pack .bottom.cause.extbug -side top -anchor w radiobutton .bottom.cause.extenh -text "External Enhancement" \ -value "external_enhancement" -variable cause -anchor w \ -command cause_changed pack .bottom.cause.extenh -side top -anchor w radiobutton .bottom.cause.extimp -text "External Improvement" \ -value "external_improvement" -variable cause -anchor w \ -command cause_changed pack .bottom.cause.extimp -side top -anchor w radiobutton .bottom.cause.chain -text "Chain Defect" -value "chain" \ -variable cause -anchor w -command cause_changed pack .bottom.cause.chain -side top -anchor w pack .bottom.cause -side left -anchor nw -pady 5 set start later frame .bottom.right frame .bottom.right.start -relief ridge -borderwidth 2 label .bottom.right.start.label -text "Begin Development:" pack .bottom.right.start.label -side top -anchor w radiobutton .bottom.right.start.immed -text "Immediately" -value "aedb" \ -variable start -anchor w -command {enable_developer_button} pack .bottom.right.start.immed -side top -anchor w radiobutton .bottom.right.start.later -text "Later" -value "later" \ -variable start -anchor w -command {disable_developer_button} pack .bottom.right.start.later -side top -anchor w pack .bottom.right.start -side top -anchor nw -pady 5 -padx 5 if { $i_am_admin } { create_admin_if_extras } pack .bottom.right -side top -anchor w pack .bottom -fill x frame .info text .info.blurb -height 3 -yscrollcommand ".info.scroll set" -wrap word \ -borderwidth 1 scrollbar .info.scroll -command ".info.blurb yview" -borderwidth 1 pack .info.scroll -side right -fill y pack .info.blurb -side left -fill both -expand 1 pack .info -side bottom -fill both -expand 1 # # This would be a good place to set a project template for change # descriptions. # set brief_description "none" set description "This change ..." set cause "internal_bug" set proj_default_test_required 1 # # Ask Aegis for the list of projects names. We use a specialized report # script which emits TCL code to set the project_list variable. # inform "Reading list of projects..." eval [read_pipe [format \ "|aereport -f %s/wish/proj_list.rpt -unf -pw=1000" $datadir] 0] inform " ...done" # # Set the project_name variable. We need to ask Aegis for this, so that # we get what *aegis* thinks is the default project name. # inform "Reading default project..." set project_name [read_pipe "|aegis -list default_project -unf" 1] inform " ...done" if { $project_name == "" } { set project_name [lindex $project_list 0] } .bdesc.text insert end $brief_description .desc.text insert end $description project_name_changed proc do_it { } { global brief_description description cause global test_nor test_bas test_reg global project_name change_number start global developer_name set filename [format "/tmp/tkaenc-%d" [pid]] set errcode "" catch { set fd [open $filename w 0600] } errcode if { $fd == "" } { inform [format "Open %s: %s" $filename $errcode] return } set brief_description [.bdesc.text get 1.0 end] set description [.desc.text get 1.0 end] set tmp $brief_description regsub -all {[\\"]} $tmp {\\&} tmp regsub -all \n $tmp \\n\\\n tmp puts $fd [format "brief_description = \"%s\";" $tmp] set tmp $description regsub -all {[\\"]} $tmp {\\&} tmp regsub -all \n $tmp \\n\\\n tmp puts $fd [format "description = \"%s\";" $tmp] puts $fd [format "cause = %s;" $cause] if { $test_nor } \ then { puts $fd "test_exempt = false;" } \ else { puts $fd "test_exempt = true;" } if { $test_bas } \ then { puts $fd "test_baseline_exempt = false;" } \ else { puts $fd "test_baseline_exempt = true;" } if { $test_reg } \ then { puts $fd "regression_test_exempt = false;" } \ else { puts $fd "regression_test_exempt = true;" } close $fd inform [format "Creating project %s change..." $project_name] set command \ [list aegis -nc -f $filename -p $project_name -o $filename.o] inform [format "Command = \"%s\"" $command] set errcode "" if {[catch { eval exec $command } errcode]} { catch { exec rm -f $filename ${filename}.o } errcode2 inform $errcode return } set change_number [read_file $filename.o] catch { exec rm -f $filename ${filename}.o } errcode2 puts [format "tkaenc: project \"%s\": change %d: created" \ $project_name $change_number] if { $start != "later" } { set command [list aegis -db -p $project_name -c $change_number] #if we are specifying the developer.. if { $developer_name != "" } { lappend command -User $developer_name } inform [format "Command = \"%s\"" $command] set errcode "" if {[catch { eval exec $command } errcode]} { catch { exec rm -f $filename } errcode2 puts [format \ "tkaenc: project \"%s\": change %d: development not begun" \ $project_name $change_number] puts $errcode exit 1 } else { puts [format \ "tkaenc: project \"%s\": change %d: development begun" \ $project_name $change_number] } } exit 0 }