class choose_repository {
-image create photo ::choose_repository::git_logo -data {
-R0lGODlh3wA9AMIHAMAAAMIKCsMKCgCAAN/v3/319f///wAAACH5BAEKAAcALAAAAADfAD0AAAP+
-aLrc/jDKSau9OOvNu/9gKI5kaZ5oqq5s675wLM90bd94ru987//AoHBILBqPyKSSFGg6n9BoUwCR
-Wq3Ux3X7zC4Xg7B4HN4Bzui0eo2GsN9wN3ye/jLI+IGZzpfz535/b3ZgeWN7goMPiXGLjGyECoaH
-Oo+QjpZ1mJlnkQaTYhigZR6cmg6mbZucnqN6F64fqZ2rmYGskbGwo7Kzt7a1lq28u6AfBcjJysvM
-yRDN0NHP0dTKniS619pG2dveQd3f4jzh40eu3eh5EOrq5kPtk3fxoQ/0xO9A93jz9+z7hvKBA1hP
-0r5/BMkIJIfvU0OE8opFXDjQWCGLEsplfEj+sUc6jg40RhDZMcdHjCNBpkQ5IuAHlx5gtjg5cWVN
-CiRjrnu5Uye/FzRlQhQ6IWcHohqQZlCKImhPm0ztqeT506dCqlddOK0K9SnOqVYphS141OuKrVm7
-cv3KUkRUC28rxMXW0KjDthvxgphb1GxSvynQilWblu1Nt4BFJZY4mIVgskMXhwQrN+GryQkj+zvx
-mFTew5/5Eo6nmV5p0pzrUr4LejTkv5mlxsZMsKlqvf1an3691PJud7JrpwZFoDgBu3Zzi/6NjrlI
-y5cD+74IPbrydowPBgfofPXe6QarW6eOuvLsBtC7424JnnX67djhtr++mTb3s+3Fe0avvexl2g3L
-laaPd4QECN9+HBioFYF2KMjff7AVtkNyBUpmnoQRNjYhg184SN94GfI2U38LeUieiIpBOGJ9JVpo
-mIYhIggUiQKZGB6GvanoGI0l9ejjj0AGKeSQRBZp5JFIJqnkkkxOkAAAOw==
-}
-
field top
field w
field w_body ; # Widget holding the center content
field w_next ; # Next button
+field w_quit ; # Quit button
field o_cons ; # Console object (if active)
field w_types ; # List of type buttons in clone
+field w_recentlist ; # Listbox containing recent repositories
+field w_localpath ; # Entry widget bound to local_path
-field action new ; # What action are we going to perform?
field done 0 ; # Finished picking the repository?
field local_path {} ; # Where this repository is locally
field origin_url {} ; # Where we are cloning from
field origin_name origin ; # What we shall call 'origin'
field clone_type hardlink ; # Type of clone to construct
field readtree_err ; # Error output from read-tree (if any)
+field sorted_recent ; # recent repositories (sorted)
constructor pick {} {
- global M1T M1B
+ global M1T M1B use_ttk NS
- make_toplevel top w
+ make_dialog top w
wm title $top [mc "Git Gui"]
if {$top eq {.}} {
menu $w.mbar -tearoff 0
$top configure -menu $w.mbar
+ set m_repo $w.mbar.repository
$w.mbar add cascade \
-label [mc Repository] \
- -menu $w.mbar.repository
- menu $w.mbar.repository
- $w.mbar.repository add command \
- -label [mc Quit] \
- -command exit \
- -accelerator $M1T-Q
+ -menu $m_repo
+ menu $m_repo
if {[is_MacOSX]} {
- $w.mbar add cascade -label [mc Apple] -menu .mbar.apple
+ $w.mbar add cascade -label Apple -menu .mbar.apple
menu $w.mbar.apple
$w.mbar.apple add command \
-label [mc "About %s" [appname]] \
-command do_about
+ $w.mbar.apple add command \
+ -label [mc "Show SSH Key"] \
+ -command do_ssh_key
} else {
$w.mbar add cascade -label [mc Help] -menu $w.mbar.help
menu $w.mbar.help
$w.mbar.help add command \
-label [mc "About %s" [appname]] \
-command do_about
+ $w.mbar.help add command \
+ -label [mc "Show SSH Key"] \
+ -command do_ssh_key
}
- _center $top 500 350
wm protocol $top WM_DELETE_WINDOW exit
bind $top <$M1B-q> exit
bind $top <$M1B-Q> exit
} else {
wm geometry $top "+[winfo rootx .]+[winfo rooty .]"
bind $top <Key-Escape> [list destroy $top]
+ set m_repo {}
}
- label $w.git_logo \
- -borderwidth 1 \
- -relief sunken \
- -background white \
- -image ::choose_repository::git_logo
- pack $w.git_logo -side top -fill x -padx 20 -pady 20
+ pack [git_logo $w.git_logo] -side left -fill y -padx 10 -pady 10
set w_body $w.body
- frame $w_body
- radiobutton $w_body.new \
- -anchor w \
- -text [mc "Create New Repository"] \
- -variable @action \
- -value new
- radiobutton $w_body.clone \
- -anchor w \
- -text [mc "Clone Existing Repository"] \
- -variable @action \
- -value clone
- radiobutton $w_body.open \
- -anchor w \
- -text [mc "Open Existing Repository"] \
- -variable @action \
- -value open
- pack $w_body.new -anchor w -fill x
- pack $w_body.clone -anchor w -fill x
- pack $w_body.open -anchor w -fill x
- pack $w_body -fill x -padx 10
+ set opts $w_body.options
+ ${NS}::frame $w_body
+ text $opts \
+ -cursor $::cursor_ptr \
+ -relief flat \
+ -background [get_bg_color $w_body] \
+ -wrap none \
+ -spacing1 5 \
+ -width 50 \
+ -height 3
+ pack $opts -anchor w -fill x
+
+ $opts tag conf link_new -foreground blue -underline 1
+ $opts tag bind link_new <1> [cb _next new]
+ $opts insert end [mc "Create New Repository"] link_new
+ $opts insert end "\n"
+ if {$m_repo ne {}} {
+ $m_repo add command \
+ -command [cb _next new] \
+ -accelerator $M1T-N \
+ -label [mc "New..."]
+ bind $top <$M1B-n> [cb _next new]
+ bind $top <$M1B-N> [cb _next new]
+ }
- frame $w.buttons
+ $opts tag conf link_clone -foreground blue -underline 1
+ $opts tag bind link_clone <1> [cb _next clone]
+ $opts insert end [mc "Clone Existing Repository"] link_clone
+ $opts insert end "\n"
+ if {$m_repo ne {}} {
+ if {[tk windowingsystem] eq "win32"} {
+ set key L
+ } else {
+ set key C
+ }
+ $m_repo add command \
+ -command [cb _next clone] \
+ -accelerator $M1T-$key \
+ -label [mc "Clone..."]
+ bind $top <$M1B-[string tolower $key]> [cb _next clone]
+ bind $top <$M1B-[string toupper $key]> [cb _next clone]
+ }
+
+ $opts tag conf link_open -foreground blue -underline 1
+ $opts tag bind link_open <1> [cb _next open]
+ $opts insert end [mc "Open Existing Repository"] link_open
+ $opts insert end "\n"
+ if {$m_repo ne {}} {
+ $m_repo add command \
+ -command [cb _next open] \
+ -accelerator $M1T-O \
+ -label [mc "Open..."]
+ bind $top <$M1B-o> [cb _next open]
+ bind $top <$M1B-O> [cb _next open]
+ }
+
+ $opts conf -state disabled
+
+ set sorted_recent [_get_recentrepos]
+ if {[llength $sorted_recent] > 0} {
+ if {$m_repo ne {}} {
+ $m_repo add separator
+ $m_repo add command \
+ -state disabled \
+ -label [mc "Recent Repositories"]
+ }
+
+ ${NS}::label $w_body.space
+ ${NS}::label $w_body.recentlabel \
+ -anchor w \
+ -text [mc "Open Recent Repository:"]
+ set w_recentlist $w_body.recentlist
+ text $w_recentlist \
+ -cursor $::cursor_ptr \
+ -relief flat \
+ -background [get_bg_color $w_body.recentlabel] \
+ -wrap none \
+ -width 50 \
+ -height 10
+ $w_recentlist tag conf link \
+ -foreground blue \
+ -underline 1
+ set home $::env(HOME)
+ if {[is_Cygwin]} {
+ set home [exec cygpath --windows --absolute $home]
+ }
+ set home "[file normalize $home]/"
+ set hlen [string length $home]
+ foreach p $sorted_recent {
+ set path $p
+ if {[string equal -length $hlen $home $p]} {
+ set p "~/[string range $p $hlen end]"
+ }
+ regsub -all "\n" $p "\\n" p
+ $w_recentlist insert end $p link
+ $w_recentlist insert end "\n"
+
+ if {$m_repo ne {}} {
+ $m_repo add command \
+ -command [cb _open_recent_path $path] \
+ -label " $p"
+ }
+ }
+ $w_recentlist conf -state disabled
+ $w_recentlist tag bind link <1> [cb _open_recent %x,%y]
+ pack $w_body.space -anchor w -fill x
+ pack $w_body.recentlabel -anchor w -fill x
+ pack $w_recentlist -anchor w -fill x
+ }
+ pack $w_body -fill x -padx 10 -pady 10
+
+ ${NS}::frame $w.buttons
set w_next $w.buttons.next
- button $w_next \
- -default active \
- -text [mc "Next >"] \
- -command [cb _next]
- pack $w_next -side right -padx 5
- button $w.buttons.quit \
+ set w_quit $w.buttons.quit
+ ${NS}::button $w_quit \
-text [mc "Quit"] \
-command exit
- pack $w.buttons.quit -side right -padx 5
+ pack $w_quit -side right -padx 5
pack $w.buttons -side bottom -fill x -padx 10 -pady 10
+ if {$m_repo ne {}} {
+ $m_repo add separator
+ $m_repo add command \
+ -label [mc Quit] \
+ -command exit \
+ -accelerator $M1T-Q
+ }
+
bind $top <Return> [cb _invoke_next]
bind $top <Visibility> "
+ [cb _center]
grab $top
focus $top
+ bind $top <Visibility> {}
"
wm deiconify $top
tkwait variable @done
+ grab release $top
if {$top eq {.}} {
eval destroy [winfo children $top]
- _center $top 500 600
}
}
-proc _home {} {
- if {[catch {set h $::env(HOME)}]
- || ![file isdirectory $h]} {
- set h .
- }
- return $h
-}
-
-proc _center {top nx ny} {
- set rx [expr {([winfo screenwidth $top] - $nx) / 2}]
- set ry [expr {([winfo screenheight $top] - $ny) / 2}]
- wm geometry $top [format {%dx%d+%d+%d} $nx $ny $rx $ry]
+method _center {} {
+ set nx [winfo reqwidth $top]
+ set ny [winfo reqheight $top]
+ set rx [expr {([winfo screenwidth $top] - $nx) / 3}]
+ set ry [expr {([winfo screenheight $top] - $ny) / 3}]
+ wm geometry $top [format {+%d+%d} $rx $ry]
}
method _invoke_next {} {
}
}
-method _next {} {
+proc _get_recentrepos {} {
+ set recent [list]
+ foreach p [get_config gui.recentrepo] {
+ if {[_is_git [file join $p .git]]} {
+ lappend recent $p
+ } else {
+ _unset_recentrepo $p
+ }
+ }
+ return [lsort $recent]
+}
+
+proc _unset_recentrepo {p} {
+ regsub -all -- {([()\[\]{}\.^$+*?\\])} $p {\\\1} p
+ git config --global --unset gui.recentrepo "^$p\$"
+ load_config 1
+}
+
+proc _append_recentrepos {path} {
+ set path [file normalize $path]
+ set recent [get_config gui.recentrepo]
+
+ if {[lindex $recent end] eq $path} {
+ return
+ }
+
+ set i [lsearch $recent $path]
+ if {$i >= 0} {
+ _unset_recentrepo $path
+ set recent [lreplace $recent $i $i]
+ }
+
+ lappend recent $path
+ git config --global --add gui.recentrepo $path
+ load_config 1
+
+ while {[llength $recent] > 10} {
+ _unset_recentrepo [lindex $recent 0]
+ set recent [lrange $recent 1 end]
+ }
+}
+
+method _open_recent {xy} {
+ set id [lindex [split [$w_recentlist index @$xy] .] 0]
+ set local_path [lindex $sorted_recent [expr {$id - 1}]]
+ _do_open2 $this
+}
+
+method _open_recent_path {p} {
+ set local_path $p
+ _do_open2 $this
+}
+
+method _next {action} {
+ global NS
destroy $w_body
+ if {![winfo exists $w_next]} {
+ ${NS}::button $w_next -default active
+ pack $w_next -side right -padx 5 -before $w_quit
+ }
_do_$action $this
}
}
method _git_init {} {
- if {[file exists $local_path]} {
- error_popup [mc "Location %s already exists." $local_path]
- return 0
- }
-
if {[catch {file mkdir $local_path} err]} {
error_popup [strcat \
[mc "Failed to create repository %s:" $local_path] \
return 0
}
+ _append_recentrepos [pwd]
set ::_gitdir .git
set ::_prefix {}
return 1
&& [file exists [file join $path config]]} {
return 1
}
+ if {[is_Cygwin]} {
+ if {[file exists [file join $path HEAD]]
+ && [file exists [file join $path objects.lnk]]
+ && [file exists [file join $path config.lnk]]} {
+ return 1
+ }
+ }
return 0
}
+proc _objdir {path} {
+ set objdir [file join $path .git objects]
+ if {[file isdirectory $objdir]} {
+ return $objdir
+ }
+
+ set objdir [file join $path objects]
+ if {[file isdirectory $objdir]} {
+ return $objdir
+ }
+
+ if {[is_Cygwin]} {
+ set objdir [file join $path .git objects.lnk]
+ if {[file isfile $objdir]} {
+ return [win32_read_lnk $objdir]
+ }
+
+ set objdir [file join $path objects.lnk]
+ if {[file isfile $objdir]} {
+ return [win32_read_lnk $objdir]
+ }
+ }
+
+ return {}
+}
+
######################################################################
##
## Create New Repository
method _do_new {} {
+ global use_ttk NS
$w_next conf \
-state disabled \
-command [cb _do_new2] \
-text [mc "Create"]
- frame $w_body
- label $w_body.h \
- -font font_uibold \
+ ${NS}::frame $w_body
+ ${NS}::label $w_body.h \
+ -font font_uibold -anchor center \
-text [mc "Create New Repository"]
pack $w_body.h -side top -fill x -pady 10
pack $w_body -fill x -padx 10
- frame $w_body.where
- label $w_body.where.l -text [mc "Directory:"]
- entry $w_body.where.t \
+ ${NS}::frame $w_body.where
+ ${NS}::label $w_body.where.l -text [mc "Directory:"]
+ ${NS}::entry $w_body.where.t \
-textvariable @local_path \
- -font font_diff \
-width 50
- button $w_body.where.b \
+ ${NS}::button $w_body.where.b \
-text [mc "Browse"] \
-command [cb _new_local_path]
+ set w_localpath $w_body.where.t
- pack $w_body.where.b -side right
- pack $w_body.where.l -side left
- pack $w_body.where.t -fill x
+ grid $w_body.where.l $w_body.where.t $w_body.where.b -sticky ew
pack $w_body.where -fill x
+ grid columnconfigure $w_body.where 1 -weight 1
+
trace add variable @local_path write [cb _write_local_path]
+ bind $w_body.h <Destroy> [list trace remove variable @local_path write [cb _write_local_path]]
update
focus $w_body.where.t
}
if {$local_path ne {}} {
set p [file dirname $local_path]
} else {
- set p [_home]
+ set p [pwd]
}
set p [tk_chooseDirectory \
if {$p eq {}} return
set p [file normalize $p]
- if {[file isdirectory $p]} {
- foreach i [glob \
- -directory $p \
- -tails \
- -nocomplain \
- * .*] {
- switch -- $i {
- . continue
- .. continue
- default {
- error_popup [mc "Directory %s already exists." $p]
- return
- }
- }
- }
- if {[catch {file delete $p} err]} {
- error_popup [strcat \
- [mc "Directory %s already exists." $p] \
- "\n\n$err"]
- return
- }
- } elseif {[file exists $p]} {
- error_popup [mc "File %s already exists." $p]
+ if {![_new_ok $p]} {
return
}
set local_path $p
+ $w_localpath icursor end
}
method _do_new2 {} {
+ if {![_new_ok $local_path]} {
+ return
+ }
if {![_git_init $this]} {
return
}
set done 1
}
+proc _new_ok {p} {
+ if {[file isdirectory $p]} {
+ if {[_is_git [file join $p .git]]} {
+ error_popup [mc "Directory %s already exists." $p]
+ return 0
+ }
+ } elseif {[file exists $p]} {
+ error_popup [mc "File %s already exists." $p]
+ return 0
+ }
+ return 1
+}
+
######################################################################
##
## Clone Existing Repository
method _do_clone {} {
+ global use_ttk NS
$w_next conf \
-state disabled \
-command [cb _do_clone2] \
-text [mc "Clone"]
- frame $w_body
- label $w_body.h \
- -font font_uibold \
+ ${NS}::frame $w_body
+ ${NS}::label $w_body.h \
+ -font font_uibold -anchor center \
-text [mc "Clone Existing Repository"]
pack $w_body.h -side top -fill x -pady 10
pack $w_body -fill x -padx 10
set args $w_body.args
- frame $w_body.args
+ ${NS}::frame $w_body.args
pack $args -fill both
- label $args.origin_l -text [mc "URL:"]
- entry $args.origin_t \
+ ${NS}::label $args.origin_l -text [mc "Source Location:"]
+ ${NS}::entry $args.origin_t \
-textvariable @origin_url \
- -font font_diff \
-width 50
- button $args.origin_b \
+ ${NS}::button $args.origin_b \
-text [mc "Browse"] \
-command [cb _open_origin]
grid $args.origin_l $args.origin_t $args.origin_b -sticky ew
- label $args.where_l -text [mc "Directory:"]
- entry $args.where_t \
+ ${NS}::label $args.where_l -text [mc "Target Directory:"]
+ ${NS}::entry $args.where_t \
-textvariable @local_path \
- -font font_diff \
-width 50
- button $args.where_b \
+ ${NS}::button $args.where_b \
-text [mc "Browse"] \
-command [cb _new_local_path]
grid $args.where_l $args.where_t $args.where_b -sticky ew
+ set w_localpath $args.where_t
- label $args.type_l -text [mc "Clone Type:"]
- frame $args.type_f
+ ${NS}::label $args.type_l -text [mc "Clone Type:"]
+ ${NS}::frame $args.type_f
set w_types [list]
- lappend w_types [radiobutton $args.type_f.hardlink \
+ lappend w_types [${NS}::radiobutton $args.type_f.hardlink \
-state disabled \
- -anchor w \
-text [mc "Standard (Fast, Semi-Redundant, Hardlinks)"] \
-variable @clone_type \
-value hardlink]
- lappend w_types [radiobutton $args.type_f.full \
+ lappend w_types [${NS}::radiobutton $args.type_f.full \
-state disabled \
- -anchor w \
-text [mc "Full Copy (Slower, Redundant Backup)"] \
-variable @clone_type \
-value full]
- lappend w_types [radiobutton $args.type_f.shared \
+ lappend w_types [${NS}::radiobutton $args.type_f.shared \
-state disabled \
- -anchor w \
-text [mc "Shared (Fastest, Not Recommended, No Backup)"] \
-variable @clone_type \
-value shared]
trace add variable @local_path write [cb _update_clone]
trace add variable @origin_url write [cb _update_clone]
+ bind $w_body.h <Destroy> "
+ [list trace remove variable @local_path write [cb _update_clone]]
+ [list trace remove variable @origin_url write [cb _update_clone]]
+ "
update
focus $args.origin_t
}
if {$origin_url ne {} && [file isdirectory $origin_url]} {
set p $origin_url
} else {
- set p [_home]
+ set p [pwd]
}
set p [tk_chooseDirectory \
}
if {$clone_type eq {hardlink} || $clone_type eq {shared}} {
- set objdir [file join $origin_url .git objects]
- if {![file isdirectory $objdir]} {
- set objdir [file join $origin_url objects]
- if {![file isdirectory $objdir]} {
- error_popup [mc "Not a Git repository: %s" [file tail $origin_url]]
- return
- }
+ set objdir [_objdir $origin_url]
+ if {$objdir eq {}} {
+ error_popup [mc "Not a Git repository: %s" [file tail $origin_url]]
+ return
}
}
}
}
+ if {[file exists $local_path]} {
+ error_popup [mc "Location %s already exists." $local_path]
+ return
+ }
+
if {![_git_init $this]} return
set local_path [pwd]
switch -exact -- $clone_type {
hardlink {
- set o_cons [status_bar::new $w_body]
- pack $w_body -fill x -padx 10
+ set o_cons [status_bar::two_line $w_body]
+ pack $w_body -fill x -padx 10 -pady 10
$o_cons start \
[mc "Counting objects"] \
[mc "buckets"]
update
+ if {[file exists [file join $objdir info alternates]]} {
+ set pwd [pwd]
+ if {[catch {
+ file mkdir [gitdir objects info]
+ set f_in [open [file join $objdir info alternates] r]
+ set f_cp [open [gitdir objects info alternates] w]
+ fconfigure $f_in -translation binary -encoding binary
+ fconfigure $f_cp -translation binary -encoding binary
+ cd $objdir
+ while {[gets $f_in line] >= 0} {
+ if {[is_Cygwin]} {
+ puts $f_cp [exec cygpath --unix --absolute $line]
+ } else {
+ puts $f_cp [file normalize $line]
+ }
+ }
+ close $f_in
+ close $f_cp
+ cd $pwd
+ } err]} {
+ catch {cd $pwd}
+ _clone_failed $this [mc "Unable to copy objects/info/alternates: %s" $err]
+ return
+ }
+ }
+
set tolink [list]
set buckets [glob \
-tails \
return
}
- set o_cons [status_bar::new $w_body]
- pack $w_body -fill x -padx 10
+ set o_cons [status_bar::two_line $w_body]
+ pack $w_body -fill x -padx 10 -pady 10
$o_cons start \
[mc "Creating working directory"] \
[mc "files"]
return
}
- set done 1
+ # -- Run the post-checkout hook.
+ #
+ set fd_ph [githook_read post-checkout [string repeat 0 40] \
+ [git rev-parse HEAD] 1]
+ if {$fd_ph ne {}} {
+ global pch_error
+ set pch_error {}
+ fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
+ fileevent $fd_ph readable [cb _postcheckout_wait $fd_ph]
+ } else {
+ set done 1
+ }
+}
+
+method _postcheckout_wait {fd_ph} {
+ global pch_error
+
+ append pch_error [read $fd_ph]
+ fconfigure $fd_ph -blocking 1
+ if {[eof $fd_ph]} {
+ if {[catch {close $fd_ph}]} {
+ hook_failed_popup post-checkout $pch_error 0
+ }
+ unset pch_error
+ set done 1
+ return
+ }
+ fconfigure $fd_ph -blocking 0
}
######################################################################
## Open Existing Repository
method _do_open {} {
+ global NS
$w_next conf \
-state disabled \
-command [cb _do_open2] \
-text [mc "Open"]
- frame $w_body
- label $w_body.h \
- -font font_uibold \
+ ${NS}::frame $w_body
+ ${NS}::label $w_body.h \
+ -font font_uibold -anchor center \
-text [mc "Open Existing Repository"]
pack $w_body.h -side top -fill x -pady 10
pack $w_body -fill x -padx 10
- frame $w_body.where
- label $w_body.where.l -text [mc "Repository:"]
- entry $w_body.where.t \
+ ${NS}::frame $w_body.where
+ ${NS}::label $w_body.where.l -text [mc "Repository:"]
+ ${NS}::entry $w_body.where.t \
-textvariable @local_path \
- -font font_diff \
-width 50
- button $w_body.where.b \
+ ${NS}::button $w_body.where.b \
-text [mc "Browse"] \
-command [cb _open_local_path]
- pack $w_body.where.b -side right
- pack $w_body.where.l -side left
- pack $w_body.where.t -fill x
+ grid $w_body.where.l $w_body.where.t $w_body.where.b -sticky ew
pack $w_body.where -fill x
+ grid columnconfigure $w_body.where 1 -weight 1
+
trace add variable @local_path write [cb _write_local_path]
+ bind $w_body.h <Destroy> [list trace remove variable @local_path write [cb _write_local_path]]
update
focus $w_body.where.t
}
if {$local_path ne {}} {
set p $local_path
} else {
- set p [_home]
+ set p [pwd]
}
set p [tk_chooseDirectory \
return
}
+ _append_recentrepos [pwd]
set ::_gitdir .git
set ::_prefix {}
set done 1