Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b14214e

Browse filesBrowse files
committed
merging doc diffs
2 parents 33ebeef + 8d414c3 commit b14214e
Copy full SHA for b14214e

File tree

Expand file treeCollapse file tree

1 file changed

+111
-2
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+111
-2
lines changed

‎githubconsole.html

Copy file name to clipboardExpand all lines: githubconsole.html
+111-2Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!doctype html>
2-
<html>
2+
<html xmlns="http://www.w3.org/1999/html">
33
<head>
44
<meta charset="utf-8">
55
<meta http-equiv="X-UA-Compatible" content="chrome=1">
@@ -72,10 +72,17 @@ <h2>Try out the Console</h2>
7272
</li>
7373
</ul>
7474

75-
<p>You will be limited to 60 requests/hour to the API (where each console command may use multipl requests). If you
75+
<p>You will be limited to 60 requests/hour to the API (where each console command may use multiple requests). If you
7676
<a href='http://josh.claassen.net/github'>authenticate via GitHub</a>, you will have a more flexible 5000 requests/hour to play with.
7777
</p>
7878

79+
<h2>Annotated Source</h2>
80+
81+
<p>The purpose of this tutorial is less about the specific code, but rather how
82+
<code>Josh.Shell</code> is wired up to a remote REST API via asynchronous calls to procude an interactive command line interface. Rather than walking through the code line by line, we will explain the flow of the GitHub console and the functions that make it possible, leaving the implementation details to the
83+
<a href="docs/githubconsole.html">annotated source code</a>. Throughout the tutorial, functions are linked to their location in the annotated source code.
84+
</p>
85+
7986
<h2>Application State</h2>
8087

8188
<p>In order for file system commands to always be available, the console must always have a current repository, which in turn means we'll always have an active user. That means that at any point in time, we will have the current user object, the list of all the user's repositories, and the root of the current branch as state. Changing users, picks a default repository and branch, so that we are never in state without this full state. Branches and current directory information are loaded on demand.</p>
@@ -118,8 +125,110 @@ <h2>The GitHub API</h2>
118125
<a href="https://github.com/sdether/josh.js/tree/github-authentication-backend">github-authentication-backend</a> branch.
119126
</p>
120127

128+
<h2>Initializing the Console</h2>
129+
130+
<p>In order for us to show the console, we have to have initialized a user, a repository and retrieved it's root directory. Because of authentication, we have two initialization paths,
131+
<strong>authenticated</strong> and <strong>unauthenticated</strong>. Both happen via
132+
<a href="docs/githubconsole.html#initialize" target="_blank"><code>initialize(access_token)</code></a>
133+
<em>(Sidenote: This is called after document.ready by an ajax response that tries to fetch the access token from our OAuth helper application).</em>
134+
</p>
135+
136+
<p>Depending on the existence of an <em>access_token</em>
137+
<a href="docs/githubconsole.html#initialize" target="_blank"><code>initialize(access_token)</code></a> will either fetch the current user and initialize a default repo or call
138+
<code>setUser</code> for a default user.</p>
139+
140+
<p>The authenticated initialization looks like this:</p>
141+
<pre>
142+
get("user", null, function(user) {
143+
if(!user) {
144+
return initializationError("user", "unable able to fetch default user");
145+
}
146+
_console.log("intializing w/ user '" + user.login + "'");
147+
return initializeRepos(user, null,
148+
function(msg) {
149+
initializationError("repo init", msg);
150+
},
151+
function(repo) {
152+
_self.user = user;
153+
initializeUI();
154+
}
155+
);
156+
});</pre>
157+
<p>All API access goes through a helper function
158+
<a href="docs/githubconsole.html#get" target="_blank"><code>get(resource, args, callback)</code></a>, which is responsible constructing the
159+
<em>jsonp</em> call and inspecting the response. For simplicity, all error conditions just result in
160+
<em>callback</em> being called with null argument instead of a
161+
<em>json</em> payload. Also for simplicity, any initialization failure, just bails out via
162+
<a href="docs/githubconsole.html#initializationError" target="_blank"><code>initializationError()</code></a>.</p>
163+
164+
<p>Once we have a user, we can call
165+
<a href="docs/githubconsole.html#initializeRepos" target="_blank"><code>initializeRepos(user, repo_name, err, callback)</code></a>, with a null repo_name to fetch all repos for the user and pick the first one as the default one, before setting the authenticated user as the current user and initializing the UI of the shell.
166+
</p>
167+
168+
<p>The unauthenticated flow simply calls
169+
<a href="docs/githubconsole.html#setUser" target="_blank"><code>setUser(user_name, repo_name, err, callback)</code></a>, which is the same function we will use to switch users later. This function follows the pattern of providing both an
170+
<em>error</em> and
171+
<em>success</em> callback, since once the shell is initialized we need to make sure that any action we take on its behalf does result in its callback being called with some value, lest the shell stop functioning. Unlike previous tutorials, we're now doing network requests and those will fail sooner or later. For this reason we need to make sure we always have a quick
172+
<em>err</em> callback to stop the current operation and call the callback provided by
173+
<code>Josh.Shell</code> on command execution. We also need to make sure that we do not mutate the application state until we are done with all operations that can fail, so that worst case is us reporting to the shell that the operation failed and our current, known good state is preserved.
174+
</p>
175+
176+
<h2>Adding Commands</h2>
177+
178+
<p>Commands are added via <code>Josh.Shell.SetCommandHandler(cmd,handler)</code> where
179+
<em>handler</em> is an object with two properties, <em>exec</em> and
180+
<em>completion</em>. The signature of the execution handler is
181+
<code>function(cmd, args, callback)</code>. Unlike the callback pattern we used for
182+
<code>setUser</code>, Josh functions never have an error handler. Since Josh interacts with the UI, it has no concept of failure -- it has to continue executing. It is up to the caller to deal with errors and transform them into the appropriate UI response. But it still gives us the flexibility to undertake an asynchronous actions, such as calling a remote API and complete the function execution upon the asynchronous return of the remote call.
183+
</p>
184+
185+
<h3><a href="docs/githubconsole.html#cmd.user" target="_blank">user [<em>username</em>]</a></h3>
186+
187+
<p>The <a href="docs/githubconsole.html#cmd.user" target="_blank"><code>user</code></a> command does not have
188+
<code>TAB</code> completion, since doing efficient tab completion against the full set of GitHub users is beyond this tutorial. Instead it expects a valid username to call
189+
<a href="docs/githubconsole.html#setUser" target="_blank"><code>setUser(user_name, repo_name, err, callback)</code></a> with and on completion renders the user template with the new current user.
190+
</p>
121191

192+
<p>If called without a <em>username</em>, we simply render user template with the current user.</p>
193+
194+
<h3><a href="docs/githubconsole.html#cmd.repo" target="_blank">repo [<em>-l | reponame</em>]</a></h3>
195+
196+
<p>The
197+
<a href="docs/githubconsole.html#cmd.repo" target="_blank"><code>repo</code></a> command can either show information about the current repository, change the current repository or list all repositories belonging to the user. It also provides
198+
<code>TAB</code> completion of partial repository names against the repositories of the current user.</p>
199+
200+
<p>Given no argument, we simply render the repository template with the current repository</p>
201+
202+
<p>If the argument is
203+
<em>-l</em>, we render the repository list template with the repositories we fetched on user initialization.</p>
204+
205+
<p>Finally, the argument is used to try and retrieve the repository from the known repositories. If that succeeds, we call
206+
<a href="docs/githubconsole.html#setRepo" target="_blank"><code>setRepo(repo, err, callback)</code></a>, which fetches the root directory to initialize the current node of
207+
<code>Josh.PathHandler</code> before changing the current repository to the one specified. Upon switching we again render the repository template with the now current repository.
208+
</p>
209+
210+
<p>The completion handler for the command simply calls
211+
<code>Josh.Shell.bestMatch</code> with the partial argument and a list of all repository names.
212+
<code>bestMatch</code> takes care of creating the completion object with the appropriate argument completion and list of possible choices.
213+
</p>
122214
</section>
215+
216+
<h3><a href="docs/githubconsole.html#cmd.branch" target="_blank">branch [<em>-l | branchname</em>]</a></h3>
217+
218+
<p>T can either show information about the current repository, change the current repository or list all repositories belonging to the user. It also provides
219+
<code>TAB</code> completion of partial repository names against the repositories of the current user.</p>
220+
221+
<p>Given no argument, the
222+
<a href="docs/githubconsole.html#cmd.branch" target="_blank"><code>branch</code></a> command simply prints the current branch name. The
223+
<em>-l</em> argument renders a list of all known branches for the current repository, while an actualy branchname as argument will cause the console to change its current branch.</p>
224+
225+
<p>Showing the list of branches uses <a href="docs/githubconsole.html#ensureBranches" target="_blank"><code>ensureBranches(err, callback)</code></a> to lazily initialize the list of branches from the API.</p>
226+
227+
<p>The completion handler for the command simply calls
228+
<code>Josh.Shell.bestMatch</code> with the partial argument and a list of all repository names.
229+
<code>bestMatch</code> takes care of creating the completion object with the appropriate argument completion and list of possible choices.
230+
</p>
231+
123232
</div>
124233
<!--[if !IE]>
125234
<script>fixScale(document);</script><![endif]-->

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.