├── .gitignore ├── LICENSE ├── tests.do ├── git.sthlp ├── README.md └── git.ado /.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Rodrigo Martell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /tests.do: -------------------------------------------------------------------------------- 1 | do "git.ado" 2 | 3 | local os = "`c(os)'" 4 | local adoPlusDir = "`c(sysdir_plus)'" 5 | if("`os'" != "Windows"){ 6 | local adoPlusDir = subinstr("`adoPlusDir'","~","/Users/`c(username)'",.) 7 | } 8 | local adoDir = trim(subinstr("`adoPlusDir'","ado/plus/","",.)) 9 | local gitDir = "`adoDir'git/" 10 | local copyCmd = "cp" /* Defaults to *nix command */ 11 | local deleteCmd = "rm" /* Defaults to *nix command */ 12 | local origDir = "`c(pwd)'" 13 | local lsCmd = "ls" /* Defaults to *nix command */ 14 | local rmdirCmd = "rm -rf" /* Defaults to *nix command */ 15 | if("`os'" == "Windows"){ 16 | local copyCmd = "copy" 17 | local deleteCmd = "erase" 18 | local lsCmd = "dir" 19 | local rmdirCmd = "rmdir /Q /S" 20 | } 21 | 22 | /*Test installing*/ 23 | git install https://github.com/coderigo/stata-switch 24 | local expectedRepoName = "stata-switch" 25 | local repoSnakeCase = "switch" 26 | capture confirm file "`gitDir'`expectedRepoName'" 27 | if _rc!=0{ 28 | di as red "Test 1 FAILED." 29 | di as red "Expected `gitDir'`expectedRepoName' to exist but it does not." 30 | } 31 | else { 32 | di as green "Test 1 PASSED." 33 | capture confirm file "`adoPlusDir's/`repoSnakeCase'.ado" 34 | if _rc!=0{ 35 | di as red "Test 2 FAILED." 36 | di "Expected `adoPlusDir's/`repoSnakeCase'.ado to exist but it does not." 37 | } 38 | else { 39 | di as green "Test 2 PASSED." 40 | } 41 | 42 | /*Test uninstalling*/ 43 | git uninstall `repoSnakeCase' 44 | capture confirm file "`gitDir'`expectedRepoName'" 45 | if _rc!=0{ 46 | di as green "Test 3 PASSED." 47 | } 48 | else{ 49 | di as red "Test 3 FAILED." 50 | di "Expected `gitDir'`expectedRepoName' to NOT exist but it does." 51 | } 52 | } 53 | 54 | /* TODO: Add more tests */ 55 | -------------------------------------------------------------------------------- /git.sthlp: -------------------------------------------------------------------------------- 1 | {smcl} 2 | {cmd:help git} {right:also see: {help ssc }} 3 | {hline} 4 | 5 | {title:Title} 6 | 7 | {p2colset 5 17 19 2}{...} 8 | {p2col :{hi: git} {hline 2}}Manage git repositories through a series of basic commands. It installs, updates, lists and removes git repositories containing Stata user-written programs. An alternative to sharing through {cmd: ssc} or {cmd: net}{p_end} 9 | {p2colreset}{...} 10 | 11 | {title:Author} 12 | 13 | {pstd} 14 | Rodrigo Martell {opt rodrigo.martell@gmail.com}. Github - {opt github.com/coderigo/stata-git}.{p_end} 15 | 16 | 17 | {title:Syntax} 18 | 19 | {p 8 13 5} 20 | {cmd:git} {it: command} 21 | 22 | {synoptset 21 tabbed}{...} 23 | {synopthdr: command} 24 | {synoptline} 25 | {synopt : {cmd:install} {it:repository}}Install program in {it:repository} (url or filepath).{p_end} 26 | {synopt : {cmd:uninstall} {it:programName}}Uninstall {it: programName} and its repository previously installed with {cmd: git install}.{p_end} 27 | {synopt : {cmd:update} {it:programName}}Update {it: programName}'s repository previously installed with {cmd: git install}.{p_end} 28 | {synopt : {cmd:list}}List all repositories managed by {cmd: git}.{p_end} 29 | 30 | {title:Description} 31 | 32 | {pstd} 33 | {opt git} Manages git repositories through a series of basic commands. It installs, updates, lists and removes git repositories containing Stata user-written programs. An alternative to sharing through {cmd: ssc} or {cmd: net}. Git repositories are saved in the same location as the {cmd: ado} and {cmd: personal} directories{p_end} 34 | 35 | {title:Creating a git repository containing a Stata module} 36 | 37 | {p 4 4 2} A few handy tips to make it work with {cmd: git}:{p_end} 38 | 39 | {p 4 4 2} 1. Use the snake-case format for your repository name and prefix it with "stata". For example, if your program {it: helloWorld}, your repository should be called {it:stata-hello-world}.{p_end} 40 | 41 | {p 4 4 3} 2. Use the {it: camelCase} for your program name and any installable other auxiliary files including the {it: .sthlp} file.{p_end} 42 | 43 | {p 4 4 3} 3. Place all the files you want to be copied over in the root of your repository.{p_end} 44 | 45 | {p 4 4 3} 4. It works nicely (and it's easier for community collaboration) if you host your repository on a public repo like {it:github}{p_end}. 46 | 47 | {title:Examples} 48 | 49 | {phang}{cmd:. git install https://github.com/coderigo/stata-switch}{p_end} 50 | {phang}{cmd:. git update switch}{p_end} 51 | {phang}{cmd:. git list}{p_end} 52 | {phang}{cmd:. git uninstall switch}{p_end} 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | Manages [git](http://git-scm.org) repositories in Stata. It installs, updates, lists and removes git repositories containing Stata user-written programs. An alternative to sharing through `ssc` or `net` 3 | 4 | ## Requirements 5 | [git](http://git-scm.org) must be installed and accessible from your command line. 6 | 7 | ## Installation 8 | 9 | ### Manually (recommended) 10 | 11 | 1. Create a directory called `git` in the same directory where your [personal ado directory](http://www.stata.com/support/faqs/programming/personal-ado-directory/) lives (i.e. make it a sibbling of your personal `ado` directory. 12 | 2. Clone this repo into the directory from **step 1** (*nix/OSX commands shown here) : `cd my/personal/directory/git && git clone https://github.com/coderigo/stata-git stata-git` 13 | 3. Copy the `.ado` and `.sthlp` files from the cloned repo from **step 2** to your [personal ado directory](http://www.stata.com/support/faqs/programming/personal-ado-directory/) under the `g` directory (create it if it does not exist). 14 | 4. Now you can keep the `git` command updated with this repo with `git update git` 15 | 16 | ### Using ssc 17 | In Stata, type: 18 | 19 | `ssc install git` 20 | 21 | **Note**: keeping stata-git up to date with the changes in this GitHub repo is easier if you install it the manual way as updates to this repo are pretty much available instantly whereas `ssc` updates can take up to a few days to get ticked through. 22 | 23 | ## Usage 24 | 25 | ### install repository 26 | Install a program from _repository_ (url or filepath) 27 | 28 | ```bash 29 | git install https://github.com/coderigo/stata-switch 30 | ``` 31 | 32 | ### uninstall program 33 | Uninstall program previously installed with `git` 34 | 35 | ```bash 36 | git uninstall switch 37 | ``` 38 | 39 | ### update program 40 | Update program previously installed with `git` 41 | 42 | ```bash 43 | git update switch 44 | ``` 45 | 46 | ### list repositories 47 | List all repositories managed by `git` 48 | 49 | ```bash 50 | git list 51 | ``` 52 | 53 | ## Creating a git repository containing a Stata module 54 | 55 | A few handy tips to make it work best `git`: 56 | 57 | 1. Use the _snake-case_ format for your repository name and prefix it with "stata". For example, if your program is called _helloWorld_, your repository should be called _stata-hello-world_. 58 | 59 | 2. Use the _camelCase_ format for your program name and any installable other auxiliary files including the _.sthlp_ file. 60 | 61 | 3. Place all the files you want to be copied over in the root of your repository. 62 | 63 | 4. It works nicely (and it's easier for community collaboration) if you host your repository on a public repo like _github_. 64 | 65 | ## Contributing 66 | Happy to take requests. 67 | Please add to the `tests.do` some sort of test, or run to make sure nothing's broken. 68 | 69 | ## Limitations 70 | 71 | 1. Have only tested this out on OSX, but feel it _should_ work the same with *nix OSs. In theory should work on Windows, but have not tested it. 72 | 73 | 2. It requires repositories and program names to follow the `snake-case` and `camelCase` format respectively (there is no obvious way to read file data into a variable with Stata. Happy to be corrected) 74 | 75 | -------------------------------------------------------------------------------- /git.ado: -------------------------------------------------------------------------------- 1 | *! version 1.1 2 | version 12.0 3 | capture program drop git 4 | program define git 5 | syntax anything(name=gitArgs id="git command and arguments") 6 | 7 | /** 8 | * This requires that you have git installed and accessible through the command line. 9 | * For instructions on installing git, see: http://git-scm.com/downloads 10 | */ 11 | di as yellow "------ WARNING:---------" 12 | di as yellow " This program requires git to be accessible through the command line." 13 | di as yellow " See http://git-scm.com/downloads" 14 | di as yellow "------------------------" 15 | /* 16 | OS-dependent vars 17 | */ 18 | local os = "`c(os)'" 19 | local adoPlusDir = "`c(sysdir_plus)'" 20 | if("`os'" != "Windows"){ 21 | local adoPlusDir = subinstr("`adoPlusDir'","~","/Users/`c(username)'",.) 22 | } 23 | local adoDir = trim(subinstr("`adoPlusDir'","ado/plus/","",.)) 24 | local gitDir = "`adoDir'git/" 25 | local copyCmd = "cp" /* Defaults to *nix command */ 26 | local deleteCmd = "rm" /* Defaults to *nix command */ 27 | local origDir = "`c(pwd)'" 28 | local lsCmd = "ls" /* Defaults to *nix command */ 29 | local rmdirCmd = "rm -rf" /* Defaults to *nix command */ 30 | if("`os'" == "Windows"){ 31 | local copyCmd = "copy" 32 | local deleteCmd = "erase" 33 | local lsCmd = "dir" 34 | local rmdirCmd = "rmdir /Q /S" 35 | } 36 | 37 | /* Make the git program dir if not there and cd to it */ 38 | /* use /nul to deal with the directory as it would be a file (for stata) */ 39 | capture confirm file "`gitDir'/nul" 40 | if _rc!=0{ 41 | capture mkdir "`gitDir'" 42 | } 43 | qui cd "`gitDir'" 44 | 45 | /* 46 | Command parsing 47 | */ 48 | if(strpos("`gitArgs'"," ") >0){ 49 | local gitCommand = trim(substr("`gitArgs'",1, strpos("`gitArgs'"," "))) 50 | } 51 | else{ 52 | local gitCommand = trim("`gitArgs'") 53 | } 54 | local gitParam1 = trim(subinstr("`gitArgs'","`gitCommand'","",1)) 55 | 56 | if("`gitCommand'" != "install" & "`gitCommand'" != "uninstall" & "`gitCommand'" != "update" & "`gitCommand'" != "list"){ 57 | di as red "`gitCommand' is not a valid git command" 58 | di as yellow "Expected one of: install, uninstal, update, list." 59 | exit 60 | } 61 | 62 | /* Translate "install" to "clone". "install" is used to be consistent with the ssc command */ 63 | if("`gitCommand'" == "install"){ 64 | 65 | /* Get the name of the repo - Stata has no equivalent to JS (or others) of string split */ 66 | local repoName = subinstr("`gitParam1'",".git","",.) 67 | local separatorPos = strpos("`repoName'","/") 68 | while `separatorPos' > 0 { 69 | local repoName = trim(substr("`repoName'", `separatorPos'+1, length("`repoName'")-`separatorPos')) 70 | local separatorPos = strpos("`repoName'","/") 71 | } 72 | 73 | /* Get the name of the command snake-cased */ 74 | local commandSnakeName = "`repoName'" 75 | local dashPos = strpos("`commandSnakeName'", "-") 76 | while `dashPos' > 0 { 77 | local commandSnakeName = trim(substr("`commandSnakeName'", `dashPos'+1, length("`commandSnakeName'")-`dashPos')) 78 | local dashPos = strpos("`commandSnakeName'", "-") 79 | } 80 | 81 | /* Create the repo */ 82 | local repoDir = "`gitDir'`repoName'/" 83 | capture confirm file "`repoDir'/nul" 84 | if _rc!=0{ 85 | capture mkdir "`repoDir'" 86 | } 87 | else{ 88 | /* Return to old directory */ 89 | di as green "`repoName' already installed" 90 | di as green "type - git update `repoName' - to get the latest and greatest." 91 | qui cd "`origDir'" 92 | exit 93 | } 94 | shell git clone "`gitParam1'" 95 | 96 | /* Copy all .ado and .sthlp files to the right directory */ 97 | local programFirstLetter = lower(substr(subinstr("`repoName'","stata-","",.),1,1)) 98 | local programDir = "../ado/plus/`programFirstLetter'/" 99 | capture confirm file "`programDir'/nul" 100 | if _rc!=0{ 101 | capture mkdir "`programDir'" 102 | } 103 | qui cd "`repoName'" 104 | shell `copyCmd' *.ado "`adoPlusDir'`programFirstLetter'" 105 | capture shell `copyCmd' *.sthlp "`adoPlusDir'`programFirstLetter'" 106 | capture shell `copyCmd' *.mmat "`adoPlusDir'`programFirstLetter'" 107 | 108 | /* Return to old directory */ 109 | qui cd "`origDir'" 110 | 111 | di as green "Done installing `commandSnakeName' from the `repoName' git repository" 112 | di as green "Type -help `commandSnakeName'-" 113 | 114 | } 115 | 116 | /* Translate "uninstall" to just removing the repo */ 117 | if("`gitCommand'" == "uninstall" | "`gitCommand'" == "update"){ 118 | 119 | /* Convert from camel case to snake case*/ 120 | local commandCamelCase = "`gitParam1'" 121 | local repoName = "stata-`commandCamelCase'" 122 | local lengthOfName = length("`repoName'") 123 | local programFirstLetter = substr("`commandCamelCase'",1,1) 124 | if(length("`repoName'") > 1){ 125 | forvalues pos = 2/`lengthOfName'{ 126 | local charAtPos = substr("`repoName'",`pos',1) 127 | if(lower("`charAtPos'") != "`charAtPos'"){ 128 | local repoName = substr("`repoName'",1,`pos'-1) + "-" + lower("`charAtPos'") + substr("`repoName'",`pos'+1,length("`repoName'")-`pos') 129 | } 130 | } 131 | } 132 | 133 | /* Translate "update" to -git pull origin- */ 134 | if("`gitCommand'" == "update"){ 135 | di as green "Checking for updates for `commandCamelCase' (git repository name: `repoName')..." 136 | qui cd "`repoName'" 137 | shell git pull origin 138 | shell `copyCmd' `commandCamelCase'.ado "`adoPlusDir'`programFirstLetter'" 139 | capture shell `copyCmd' `commandCamelCase'.sthlp "`adoPlusDir'`programFirstLetter'" 140 | capture shell `copyCmd' `commandCamelCase'.mmat "`adoPlusDir'`programFirstLetter'" 141 | qui cd "`origDir'" 142 | } 143 | 144 | /* Uninstall nukes all */ 145 | if("`gitCommand'" == "uninstall"){ 146 | capture confirm file "`repoName'/nul" 147 | if _rc!=0{ 148 | di as red "-`commandCamelCase'- not installed via -git- command" 149 | } 150 | else{ 151 | qui shell `rmdirCmd' `repoName' 152 | qui cd "`adoPlusDir'`programFirstLetter'" 153 | qui erase "`commandCamelCase'.ado" 154 | qui capture erase "`commandCamelCase'.sthlp" 155 | qui capture erase "`commandCamelCase'.mmat" 156 | qui cd "`origDir'" 157 | di as green "Git repository `repoName' and command -`commandCamelCase'- removed." 158 | } 159 | } 160 | 161 | } 162 | 163 | /* "list" lists all git-managed repos */ 164 | if("`gitCommand'" == "list"){ 165 | di as yellow "Git repositories installed using -git- command in" 166 | di as yellow "`gitDir':" 167 | di as green "note: when used in Stata, the stata- prefix is stripped and the " 168 | di as green " program name is snake-cased" 169 | di as green " e.g. repository stata-my-program becomes -myProgram- when used in Stata" 170 | shell `lsCmd' 171 | qui cd "`origDir'" 172 | } 173 | 174 | end 175 | --------------------------------------------------------------------------------