*! version 1.0.4 11nov2005 program adoupdate, rclass version 9 syntax [anything(name=pkglist id="package list")] [, /// ALL /// DIR(string) /// SSConly /// UPDATE /// VERBOSE /// ] local upd = cond("`update'"=="", 0, 1) local bos = cond("`ssconly'"=="", 0, 1) local notall = cond("`all'"=="", 1, 0) local noisily = cond("`verbose'"=="", 0, 1) set more off mata: pkg_chk_and_update("`dir'", "`pkglist'", /// `upd', `bos', `notall', `noisily') return local pkglist "`pkglist'" end /* ==================================================================== */ version 9 local CMDNAME adoupdate local DEFAULT_DIR "PLUS" local SJupfile `""http://www.stata-journal.com/software/filelist.php""' local SJbasesrc `""http://www.stata-journal.com/software/""' local STBupfile `""http://www.stata.com/stb/filelist.php""' local STBbasesrc `""http://www.stata.com/stb/""' local SSCupfile `""http://repec.org/docs/sscDD.php""' local NEGRC_NORESPONSE (-677) local NEGRC_NOHOST (-631) local NEGRC_NOFILE (-601) local boolean real scalar local instpkg string colvector local instlist pointer(`instpkg') colvector local EL_relno 1 local EL_upsrc 2 local EL_uppkgname 3 local EL_FIRST 4 local updlist pointer(string colvector) colvector local L_SJ 1 local L_STB 2 local L_SSC 3 local UPDLIST_DIM 3 local pkgcode real scalar local PKG_OKAY 0 local PKG_NOLONGER 1 local PKG_NORESPONSE 2 local PKG_CANNOTOPEN 3 local PKG_UNKNOWN 4 local PKG_UPDATED 5 local pkgtype real scalar local PT_INSTALLED 1 local PT_NET 2 mata: mata set matastrict on /* -------------------------------------------------------------------- */ void pkg_chk_and_update( string scalar dir, string scalar pkglist, `boolean' update, `boolean' ssconly, `boolean' certainonly, `boolean' noisily) { `instlist' trk `updlist' upd string scalar click /* ------------------------------------------------------------ */ openingmsg() upd = J(`UPDLIST_DIM', 1, NULL) /* ------------------------------------------------------------ */ find_and_uninst_dups(dir, 1) /* ------------------------------------------------------------ */ trk = read_statatrk(dir) if (ssconly) trk = extract_ssc(trk) if (pkglist!="") trk = extract_matches(trk, pkglist) /* ------------------------------------------------------------ */ if (rows(trk)==0) { printf("{txt}") if ("pkglist"!="") { printf(`"(no packages match "%s")\n"', pkglist) } else if (ssconly) { printf("(no packages installed from SSC\n") } else { printf("(no user-written packages installed)\n") } return } /* ------------------------------------------------------------ */ printf("\n") printf("{txt}Checking status of ") printf(pkglist=="" ? "installed packages...\n": "specified packages...\n") trk = extract_update_exists(trk, upd, certainonly) /* ------------------------------------------------------------ */ printf("\n") if (rows(trk)==0) { printf("{txt}(no packages require updating)\n") return } printf(update ? "{txt}Packages to be updated are...\n" : "{txt}Packages that need to be updated are...\n" ) printf("\n") list_packages(trk) set_local_pkglist(trk) displayflush() /* ------------------------------------------------------------ */ printf("\n") if (!update) { click = rebuildcmdwupdate(dir, pkglist, ssconly, certainonly) printf("{txt}Recommendation: type\n") printf(`" {stata `"%s"':%s}\n"', click, click) return } /* ------------------------------------------------------------ */ printf("{txt}Installing updates...\n") printf("\n") update_packages(dir, trk, noisily) /* ------------------------------------------------------------ */ printf("\n") printf("{txt}Cleaning up...") displayflush() find_and_uninst_dups(dir, 0) printf("{txt} Done\n") displayflush() } void openingmsg() { printf("{txt}{p 0 7 2}\n") printf("(note: {cmd:`CMDNAME'} updates user-written files;\n") printf("type -{cmd:update}- to check for updates to official Stata)\n") printf("{p_end}\n") } string scalar rebuildcmdwupdate( string scalar dir, string scalar pkglist, `boolean' ssconly, `boolean' certainonly) { string scalar cmd cmd = "`CMDNAME'" if (strtrim(pkglist)!="") cmd = cmd + " " + strtrim(pkglist) cmd = cmd + "," if (dir!="") cmd = cmd + " dir(" + dir + ")" if (ssconly) cmd = cmd + " ssconly" if (!certainonly) cmd = cmd + " all" return(cmd + " update") } /* -------------------------------------------------------------------- */ `instlist' extract_ssc(`instlist' trk) { real scalar i `instlist' b pragma unset b for (i=1; i<=rows(trk); i++) { if (isssc(srcof(*trk[i]))) b = b \ trk[i] } return(b) } `instlist' extract_matches(`instlist' trk, string scalar pkglist) { real scalar i, j `instlist' in string rowvector pat pragma unset in pat = tokens(pkglist) for (i=1; i<=rows(trk); i++) { for (j=1; j<=cols(pat); j++) { if (strmatch(pkgnameof(*trk[i]), pat[j])) { in = in \ trk[i] break } } } return(in) } /* -------------------------------------------------------------------- */ void update_packages(string scalar dir, `instlist' trk, `boolean' noisily) { real scalar i for (i=1; i<=rows(trk); i++) { netinstall(dir, *trk[i], noisily) } } void netinstall(string scalar dir, `instpkg' pkg, `boolean' noisily) { string scalar uppkgname, pkgname, upsrc, cmd, cmd0 real scalar rc, relno pkgname = pkgnameof(pkg) uppkgname = uppkgnameof(pkg) upsrc = upsrcof(pkg) relno = relnoof(pkg) printf("{txt}") printf(relno<10 ? " " : (relno<100 ? " " : " ")) if (pkgname == uppkgname) { printf("[%g] {res:%s}\n", relno, pkgname) } else { printf("[%g] {res:%s} using {res:%s}\n", relno, pkgname, uppkgname) } displayflush() cmd0 = sprintf("net set ado %s", dir=="" ? "`DEFAULT_DIR'" : dir) if (isssc(upsrc)) { cmd = sprintf("ssc install %s, replace", uppkgname) } else { cmd = sprintf("net install %s, from(%s) replace", uppkgname, upsrc) } if (noisily) { printf("\n") printf("{txt}{hline}\n") printf("{txt}-> . %s\n", cmd0) if ((rc = _stata(cmd0))) exit(rc) printf("{txt}-> . %s\n", cmd) rc = _stata(cmd) printf("{txt}{hline}\n") } else { if ((rc = _stata(cmd0, 1))) { if (rc==1) exit(1) (void) _stata(cmd0) exit(rc) /*NOTREACHED*/ } rc = _stata(cmd, 1) } if (rc) { if (rc==1) exit(1) printf("{p 8 8 2}\n") printf("{txt}{res:%s} not updated; return code was %g{break}\n", pkgname, rc) printf("Try updating {res:%s} again later,\n", pkgname) printf("type -{cmd:`CMDNAME' %s, update}-.\n", pkgname) printf("If that still does not work, type\n") printf("-{cmd:`CMDNAME' %s, update verbose}-.\n", pkgname) printf("\n") } } void set_local_pkglist(`instlist' trk) { real scalar i string scalar list if (rows(list)==0) return list = pkgnameof(*trk[1]) for (i=2; i<=rows(trk); i++) list = list + " " + pkgnameof(*trk[i]) st_local("pkglist", list) } void list_packages(`instlist' trk) { real scalar i, n, relno string scalar pkgname, pad for (i=1; i<=rows(trk); i++) { pkgname = pkgnameof(*trk[i]) if ((n = 12 - strlen(pkgname)) > 0) { pad = "{bind:" + n*" " + "}" } else pad = "" relno = relnoof(*trk[i]) if (relno<10) printf("{p 4 24 2}\n") else if (relno<100) printf("{p 3 24 2}\n") else printf("{p 2 24 2}\n") printf("[%g] {res:%s}%s -- %s\n", relno, pkgname, pad, titleof(*trk[i])) printf("{p_end}\n") } } `instlist' extract_update_exists(`instlist' trk, `updlist' upd, `boolean' certainonly) { real scalar i `pkgcode' status `instlist' res pragma unset res status = J(rows(trk), 1, .) for (i=1; i<=rows(trk); i++) { status = pkg_update_status_noisily(*trk[i], upd) if (status==`PKG_UPDATED' | (certainonly==0 & status==`PKG_UNKNOWN')) { res = res \ trk[i] } } return(res) } `pkgcode' pkg_update_status_noisily(`instpkg' pkg, `updlist' upd) { real scalar relno `pkgcode' res printf("\n") relno = relnoof(pkg) if (relno<10) printf("{p 4 8 2}\n") else if (relno<100) printf("{p 3 8 2}\n") else printf("{p 2 8 2}\n") printf("{txt}[%g] {res:%s} at %s:{break}\n", relno, pkgnameof(pkg), srcof(pkg)) displayflush() res = pkg_update_status(pkg, upd) if (res==`PKG_OKAY') { printf("installed package is up to date\n") } else if (res==`PKG_CANNOTOPEN') { printf( "server not responding or package is no longer available\n") } else if (res==`PKG_NOLONGER') { printf("package no longer available\n") } else if (res==`PKG_NORESPONSE') { printf("server not responding\n") } else if (res==`PKG_UPDATED') { printf("{res:package has been updated on server}\n") } else { printf( "cannot tell because distribution dates not provided by source\n") } printf("{p_end}\n") displayflush() return(res) } `pkgcode' pkg_update_status(`instpkg' pkg, `updlist' upd) { string scalar src src = srcof(pkg) if (isssc(src)) return(pkg_update_status_ssc(pkg, upd)) if (isstatajournal(src)) return(pkg_update_status_sj( pkg, upd)) if (isstb(src)) return(pkg_update_status_stb(pkg, upd)) return(pkg_update_status_default(pkg)) } `boolean' isstb(string scalar s) { string scalar sl sl = strlower(s) if (pstrcmp("http://www.stata.com/stb/", sl)) return(1) return(0) } `boolean' isstatajournal(string scalar s) { string scalar sl sl = strlower(s) if (pstrcmp("http://www.stata-journal.com/software/", sl)) return(1) if (pstrcmp("http://www.statajournal.com/software/", sl)) return(1) if (pstrcmp("http://www.stata-journal.org/software/", sl)) return(1) if (pstrcmp("http://www.statajournal.org/software/", sl)) return(1) return(0) } `boolean' isssc(string scalar s) { string scalar sl sl = strlower(s) if (pstrcmp("http://fmwww.bc.edu/repec/", sl)) return(1) return(0) } `boolean' pstrcmp(string scalar substr, string scalar fullstr) { return( (substr == substr(fullstr, 1, strlen(substr))) ) } `pkgcode' pkg_update_status_ssc(`instpkg' pkg, `updlist' upd) { real scalar dinstalled, dnet string scalar strdate if (upd[`L_SSC']==NULL) { upd[`L_SSC'] = &(loadsscupfile()) /* testing of bsearch: printf("\n") i = rows(*upd[`L_SSC']) i (*upd[`L_SSC'])[1] (*upd[`L_SSC'])[i] bsearch_ssclist("_gclsort", *upd[`L_SSC'], 0) bsearch_ssclist("ztg", *upd[`L_SSC'], 0) */ } strdate = search_ssclist(pkgnameof(pkg), *upd[`L_SSC']) if (strdate=="") return(`PKG_NOLONGER') dinstalled = distributiondateof(pkg, `PT_INSTALLED') dnet = edateofstr(strdate) if (dinstalled<. & dnet<.) { if (dinstalled=.) { set_upinfoof(pkg, srcof(pkg), pkgnameof(pkg)) return(`PKG_UPDATED') } return(`PKG_UNKNOWN') } string scalar search_ssclist(string scalar pkgname, string colvector ssclist) { real scalar i if (i = bsearch_ssclist(strlower(pkgname), ssclist, 0)) { return(tokens(ssclist[i])[2]) } return("") } /* i = bsearch_ssclist(name, ssclist, i0) Look for name in strictly ascending ssclist[] between i0 and end-of-list. Specify i0=0 to search entire list. */ real scalar bsearch_ssclist(string scalar name, string vector ssclist, real scalar j0) { real scalar n, jl, ju, jm jl = j0 ju = (n=length(ssclist)) + 1 while (ju-jl>1) { jm = trunc((ju+jl)/2) if ( name > (tokens(ssclist[jm])[1]) ) jl = jm else ju = jm } if (jl=.) { set_upinfoof(pkg, srcof(pkg), pkgnameof(pkg)) return(`PKG_UPDATED') } return(`PKG_UNKNOWN') } `pkgcode' pkg_update_status_stb(`instpkg' pkg, `updlist' upd) { real scalar idx string scalar pkgname if (pkg_update_status_sj(pkg, upd)==`PKG_UPDATED') { return(`PKG_UPDATED') } pkgname = pkgnameof(pkg) if (upd[`L_STB']==NULL) upd[`L_STB'] = &loadupfile(`STBupfile') if (idx = findbestinlist(pkgname, *upd[`L_STB'])) { set_upinfo_fromupd(pkg, upd, `L_STB', idx, `STBbasesrc') return(`PKG_UPDATED') } return(`PKG_OKAY') } `pkgcode' pkg_update_status_sj(`instpkg' pkg, `updlist' upd) { real scalar idx string scalar pkgname pkgname = pkgnameof(pkg) if (upd[`L_SJ']==NULL) upd[`L_SJ'] = &loadupfile(`SJupfile') if (idx = findbestinlist(pkgname, *upd[`L_SJ'])) { set_upinfo_fromupd(pkg, upd, `L_SJ', idx, `SJbasesrc') return(`PKG_UPDATED') } return(`PKG_OKAY') } void set_upinfo_fromupd(`instpkg' pkg, `updlist' upd, real scalar l, real scalar i, string scalar basesrc) { string rowvector toks toks = tokens((*upd[l])[i]) set_upinfoof(pkg, pathjoin(basesrc,toks[1]), toks[2]) } string colvector loadupfile(string scalar ffn) { real scalar fh string scalar line string colvector res fh = fopen(ffn, "r") pragma unset res while ((line=fget(fh))!=J(0,0,"")) { if (strpos(line, "_")) res = res \ line } fclose(fh) return(res) } string colvector loadsscupfile() { real scalar fh string scalar line string colvector res fh = fopen(`SSCupfile', "r") pragma unset res while ((line=fget(fh))!=J(0,0,"")) { if (line!="") { res = res \ strlower(subinstr(line,":","",1)) } } fclose(fh) _sort(res, 1) return(res) } real scalar findbestinlist(string scalar name, string colvector list) { string scalar curlhs, newlhs, newname real scalar currhs, newrhs real scalar i, bestidx, bestrhs pragma unset newlhs pragma unset newrhs pragma unset curlhs pragma unset currhs splitname(name, curlhs, currhs) bestrhs = currhs bestidx = 0 for (i=1; i<=rows(list); i++) { newname = tokens(list[i])[2] splitname(newname, newlhs, newrhs) if (newlhs == curlhs) { if (newrhs>bestrhs) { bestrhs = newrhs bestidx = i } } } return(bestidx) } void splitname(string scalar name, lhs, rhs) { real scalar i if (i = strpos(name, "_")) { lhs = substr(name, 1, i-1) rhs = strtoreal(substr(name, i+1, .)) if (rhs<.) return } lhs = name rhs = -1 } string scalar basepkgname(string scalar name) { real scalar i i = strpos(name, "_") return(i ? substr(name, 1, i-1) : name) } /* -------------------------------------------------------------------- */ void find_and_uninst_dups(string scalar dir, `boolean' noisily) { while (1) { if (find_and_uninst_1dup_std(dir, noisily)==0) break } while (1) { if (find_and_uninst_1dup_sjstb(dir, noisily)==0) break } while (1) { if (find_and_uninst_1dup_ssc(dir, noisily)==0) break } } `boolean' find_and_uninst_1dup_std(string scalar dir, `boolean' noisily) { `instlist' trk string colvector lcffn string scalar lcpkgname real scalar i, j trk = read_statatrk(dir) lcffn = J(rows(trk), 1, "") for (i=1; i<=rows(trk); i++) lcffn[i] = strlower(srcffnof(*trk[i])) for (i=1; irhs[j] ? j:i) netrm(dir, *trk[torm], noisily) return(1) } } } } } return(0) } void rmdup(string scalar dir, `instlist' trk, real scalar i, real scalar j, `boolean' noisily) { real scalar idate, jdate, torm idate = installdateof(*trk[i]) jdate = installdateof(*trk[j]) if (idate>jdate) torm = j else if (idateuniqidof(*trk[j])) torm = j else torm = i } netrm(dir, *trk[torm], noisily) } void netrm(string scalar dir, `instpkg' pkg, `boolean' noisily) { string scalar cmd if (noisily) { printf("{p}\n") printf( "{txt}(note: package {res:%s} was installed more than once;\n", pkgnameof(pkg)) printf("older copy removed)\n") printf("{p_end}\n") } cmd = sprintf("quietly ado uninstall [%g]", relnoof(pkg)) if (dir!="") cmd = cmd + ", from("+dir+")" stata(cmd) } /* -------------------------------------------------------------------- */ `instlist' read_statatrk(string scalar dir) { real scalar fh, i string scalar element `instlist' res res = J(0,1,NULL) if ((fh = _fopen(ffn_of_statatrk(dir), "r")) < 0) { errprintf( "directory %s does not have user-installed files\n", dir) exit(601) } i = 0 while((element=read_statatrk_element(fh, ++i))!=J(0,1,"")) { res = res \ &acopy(element) } fclose(fh) return(res) } string scalar ffn_of_statatrk(string scalar dir) { string scalar basedir basedir = pathsubsysdir(dir=="" ? "`DEFAULT_DIR'" : dir) return(pathjoin(basedir, "stata.trk")) } transmorphic matrix acopy(transmorphic matrix x) { transmorphic matrix copy copy = x return(copy) } void read_statatrk_skiphdr(real scalar fh) { string scalar line real scalar pos pos = ftell(fh) while ((line=fget(fh))!=J(0,0,"")) { if (!(substr(line,1,1)=="*" | strtrim(line)=="")) { fseek(fh, pos, -1) return } pos = ftell(fh) } } `instpkg' read_statatrk_element(real scalar fh, real scalar i) { `instpkg' res string scalar line res = J(`EL_FIRST', 1, "") res[`EL_relno'] = sprintf("%g", i) read_statatrk_skiphdr(fh) if ((line = fget(fh))==J(0,0,"")) return(J(0,1,"")) if (substr(line, 1, 1)!="S") { errprintf("stata.trk file invalid header\n") exit(610) } res[`EL_FIRST'] = line while ((line=fget(fh))!=J(0,0,"")) { if (line!="" & substr(line,1,1)!="*") { res = res \ strrtrim(line) if (substr(line,1,1)=="e") return(res) } } errprintf("stata.trk file invalid contents\n") exit(610) /*NOTREACHED*/ } /* -------------------------------------------------------------------- */ real scalar read_pkg_file(string scalar ffn, string colvector res) { real scalar fh if ((fh = _fopen(ffn, "r")) < 0) { res = J(0, 1, "") return(fh) } res = read_pkg_element(fh) fclose(fh) return(0) } string colvector read_pkg_element(real scalar fh) { string colvector res string scalar line pragma unset res while ((line=fget(fh))!=J(0,0,"")) { if (line!="" & substr(line,1,1)!="*") { res = res \ strrtrim(line) } } return(res) } /* -------------------------------------------------------------------- */ string scalar srcof(`instpkg' pkg) { return(subelementof(pkg, "S")) } string scalar titleof(`instpkg' pkg) { string colvector res res = subelementof(pkg, "d") return(rows(res)==0 ? "" : res[1]) } string scalar upsrcof(`instpkg' pkg) { return(pkg[`EL_upsrc']) } string scalar srcffnof(`instpkg' pkg) { string scalar src, fn src = srcof(pkg) fn = subelementof(pkg, "N") if (rows(src)!=1 | rows(fn)!=1) return("") return(pathjoin(src, fn)) } string scalar pkgnameof(`instpkg' pkg) { string colvector res real scalar len res = subelementof(pkg, "N") if (rows(res)!=1) return("") len = strlen(res) if (substr(res, len-3, .) == ".pkg") return(substr(res, 1, len-4)) return(res) } string scalar uppkgnameof(`instpkg' pkg) { return(pkg[`EL_uppkgname']) } real scalar uniqidof(`instpkg' pkg) { string colvector res real scalar uid res = subelementof(pkg, "U") if (rows(res)==1) { uid = strtoreal(res) if (uid<.) return(uid) } pkg_corrupt() /*NOTREACHED*/ } real scalar relnoof(`instpkg' pkg) { real scalar rel if ((rel = strtoreal(pkg[`EL_relno'])) < .) return(rel) pkg_corrupt() /*NOTREACHED*/ } real scalar installdateof(`instpkg' pkg) { string colvector res string scalar edate res = subelementof(pkg, "D") if (rows(res)==1) { edate = date(res, "dmy") if (edate<.) return(edate) } pkg_corrupt() /*NOTREACHED*/ } real scalar distributiondateof(`instpkg' pkg, `pkgtype' ptype) { real scalar i string colvector d real scalar e, emax d = distributiondatesof(pkg, ptype) emax = 0 for (i=1; i<=rows(d); i++) { e = edateofstr(d[i]) if (e>emax & e<.) emax = e } return(emax ? emax : .) } string colvector distributiondatesof(`instpkg' pkg, `pkgtype' ptype) { real scalar i string colvector d string colvector res d = (ptype==`PT_INSTALLED' ? subelementof(pkg, "d") : subelementnet(pkg, "d") ) pragma unset res for (i=1; i<=rows(d); i++) { /* ----+----1----+--- */ /* Distribution-Date: */ if (strlower(substr(d[i], 1, 18))=="distribution-date:") { res = res \ strlower(strtrim(substr(d[i], 19, .))) } } return(res) } string colvector subelementof(`instpkg' pkg, string scalar ltr) { real scalar i string colvector res pragma unset res for (i=`EL_FIRST'; i<=rows(pkg); i++) { if (substr(pkg[i],1,1)==ltr) { res = res \ strtrim(substr(pkg[i],2,.)) } } return(res) } string colvector subelementnet(string colvector gel, string scalar ltr) { real scalar i string colvector res pragma unset res for (i=1; i<=rows(gel); i++) { if (substr(gel[i],1,1)==ltr) { res = res \ strtrim(substr(gel[i],2,.)) } } return(res) } void set_upinfoof(`instpkg' pkg, string scalar src, string scalar pkgname) { pkg[`EL_upsrc'] = src pkg[`EL_uppkgname'] = pkgname } void pkg_corrupt() { errprintf("stata.trk file invalid or corrupted\n") errprintf("no action taken\n") exit(610) /*NOTREACHED*/ } /* -------------------------------------------------------------------- */ real scalar edateofstr(string scalar s) { real scalar res real scalar yr, mo, da if (strlen(s)==8) { yr = strtoreal(substr(s, 1, 4)) mo = strtoreal(substr(s, 5, 2)) da = strtoreal(substr(s, 7, 2)) if (yr<. & mo<. & da<.) { res = mdy(mo, da, yr) if (res!=.) return(res) } } return(date(s, "dmy")) } real scalar docmd(string scalar rhs) { real scalar res stata("scalar DoCmdStringScalar = " + rhs) res = st_numscalar("DoCmdStringScalar") stata("scalar drop DoCmdStringScalar") return(res) } real scalar mdy(real mo, real da, real yr) { return(docmd(sprintf("mdy(%g, %g, %g)", mo, da, yr))) } real scalar date(string scalar str, string scalar pattern) { return(docmd(sprintf(`"date("%s", "%s")"', str, pattern))) } /* -------------------------------------------------------------------- */ end