Advanced topics—self updating

Imagine that you have just created your ideal, perfect application, wrapped into an easy-to-use self-executing file and made it available for public. People start using it, the count of downloads is getting higher every day, and suddenly you discover a terrible bug causing your software to be barely usable! Your product goes from 'wonderful' to 'pitiful' within moments.

And what if you manage a network with thousands of computers, each of them running your (defective) utility? Will you spend your entire weekend running from one computer to another and replacing the software manually?

Such scenarios have long been the worst nightmare of almost every software developer. The solution? Of course, the possibility of bugs can't be eliminated, but you can take care to minimize the impact of bugs on your users, and to be able to react as fast as possible by facilitating the process of replacing the bad software with a working version with the help of a blessed feature called autoupdate.

Of course, software defects are not the only reason to create a newer version of your application. You may new features to it, or make modifications, optimizations, and improvements. As part of easing deployment and management, you may want your application to automatically update itself. As the book deals with network programming, we assume that the update will be available to download over the network, and that every computer running the software is connected to that network.

Depending on how the application will work, there are different scenarios that we will consider. One option is that it will be a daemon running in the background—in this case, it is best to simply schedule periodic checking for updates, possibly with some smart algorithm to prevent all instances being updated at once, and therefore, generating network overload. The second option is an application that is started, used and eventually closed—in this scenario, the most obvious solution is to check for updates at start time.

Knowing the importance of automatic update, let's take a closer look at how to adopt this in terms of Starpack files. For the sake of simplicity, in the rest of this section, we assume that 'the update' that will be downloaded is a newer, full version of the application—in other words, we will not consider incremental updates.

Why do we focus on Starpacks and not Starkits? Starkits have the ability to modify their contents in terms of normal write operations to VFS, and that makes updating them as easy as downloading new VFS contents and replacing the old ones.

Starpacks, however, do not provide for such a possibility. On many operating systems (including all Microsoft Windows versions and many Unix variants), it is not possible to write to a file that is currently being run—that is, to replace our own binary file. Therefore, a typical approach is to use an additional binary for performing the upgrade.

Assuming our executable is in<dirname> and is called<filename>, after detecting and downloading an update, the steps to update our binary will be similar to the following:

  1. First of all, part of the autoupdate code will write a new version of the binary as<dirname>/autoupdate-<filename>. Next, it will run<dirname>/autoupdate-<filename>, optionally passing to it all arguments that were passed to the original binary, and exit the main binary.
  2. Now the autoupdate binary (which writes to our main application's executable file, because it is a separate file that is not being executed at the moment) will copy<dirname>/autoupdate-<filename> as<dirname>/<filename>. This can be implemented so that the initialization of the application checks the filename, and if it matches a specific pattern, performs the autoupdate actions. For example, we can check this by using:
    set dirname [file dirname [info nameofexecutable]]
    if {[regexp "^autoupdate-(.*)" 
    [file tail [info nameofexecutable]] - binaryname]} {
    
  3. First, the name of the directory where the binary is located is stored in the $dirname variable, as it will be useful later. The check is performed by getting the name of the binary file (additionally, it is saved in the $binaryname variable) and checking if the filename begins with autoupdate-. If the filename matches with it, we'll perform autoupdate actions as follows:
    after 5000
    set targetname [file join $dirname $binaryname]
    

    The code waits for 5 seconds for the parent process to exit—this is a relatively safe assumption, but some developers recommend using a wait of of 30 seconds.

  4. Next, the main binary will be overwritten, make sure it can be run on Unix systems and eventually executed. Before that, we need to try and unmount our autoupdate the binary's VFS; this is required in order to copy our binary, otherwise Tcl would try to copy mounted VFS contents instead of the file itself, because the mountpoint name and filename are the same.
    catch {vfs::mk4::Unmount exe [info nameofexecutable]}
    file copy -force [info nameofexecutable] $targetname
    catch {file attributes $targetname -permissions 0755}
    exec $targetname {*}$argv &
    exit 0
    

    This will cause the autoupdate binary to exit and main binary to be run again, but this time it will be a newer, updated version of the binary that is run. exe is the name of a handle for the mounted VFS used internally by Tclkit.

  5. As a cleanup step you should delete the autoupdate binary from the main binary if it exists at startup time. You can simply add the following code to check if the initial condition of a file with a name matching the autoupdate- prefix is met:
    } else {
    set autoupdatename [file join $dirname 
    autoupdate-[file tail [info nameofexecutable]]
    if {[file exists $autoupdatename]} {
    after 5000
    catch {file delete -force $autoupdatename}
    }
    }
    

    There is a delay of 5 seconds before trying to delete the autoupdate binary. This is needed because of the delay between the beginning of the new process and the termination of the old one.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.124.177