Skip to content
Browse files

Merge pull request #22 from ngrunwald/contents

add the three routes from the contents API
  • Loading branch information...
2 parents eb14c22 + 2b883ec commit 5d5a45d3ea32e5bbc8e9d09554acae71fc6b0224 @Raynes committed Jan 28, 2013
Showing with 81 additions and 17 deletions.
  1. +2 −1 project.clj
  2. +26 −14 src/tentacles/core.clj
  3. +53 −2 src/tentacles/repos.clj
View
3 project.clj
@@ -6,4 +6,5 @@
:dependencies [[org.clojure/clojure "1.4.0"]
[clj-http "0.4.0"]
[cheshire "4.0.0"]
- [com.cemerick/url "0.0.6"]])
+ [com.cemerick/url "0.0.6"]
+ [org.clojure/data.codec "0.1.0"]])
View
40 src/tentacles/core.clj
@@ -65,11 +65,12 @@
(str url (apply format end-point (map #(URLEncoder/encode (str %) "UTF-8") positional))))
(defn make-request [method end-point positional query]
- (let [all-pages? (query "all_pages")
- req (merge-with merge
+ (let [req (merge-with merge
{:url (format-url end-point positional)
:basic-auth (query "auth")
:throw-exceptions (or (query "throw_exceptions") false)
+ :follow-redirects (let [over (get query "follow_redirects" ::not-found)]
+ (if (= over ::not-found) true over))
:method method}
(when (query "accept")
{:headers {"Accept" (query "accept")}})
@@ -78,23 +79,34 @@
proper-query (dissoc query "auth" "oauth_token" "all_pages" "accept")
req (if (#{:post :put :delete} method)
(assoc req :body (json/generate-string (or (proper-query "raw") proper-query)))
- (assoc req :query-params proper-query))
- exec-request-one (fn exec-request-one [req]
- (safe-parse (http/request req)))
- exec-request (fn exec-request [req]
- (let [resp (exec-request-one req)]
- (if (and all-pages? (-> resp meta :links :next))
- (let [new-req (update-req req (-> resp meta :links :next))]
- (lazy-cat resp (exec-request new-req)))
- resp)))]
- (exec-request req)))
+ (assoc req :query-params proper-query))]
+ req))
(defn api-call
([method end-point] (api-call method end-point nil nil))
([method end-point positional] (api-call method end-point positional nil))
([method end-point positional query]
- (let [query (query-map query)]
- (make-request method end-point positional query))))
+ (let [query (query-map query)
+ all-pages? (query "all_pages")
+ req (make-request method end-point positional query)
+ exec-request-one (fn exec-request-one [req]
+ (safe-parse (http/request req)))
+ exec-request (fn exec-request [req]
+ (let [resp (exec-request-one req)]
+ (if (and all-pages? (-> resp meta :links :next))
+ (let [new-req (update-req req (-> resp meta :links :next))]
+ (lazy-cat resp (exec-request new-req)))
+ resp)))]
+ (exec-request req))))
+
+(defn raw-api-call
+ ([method end-point] (raw-api-call method end-point nil nil))
+ ([method end-point positional] (raw-api-call method end-point positional nil))
+ ([method end-point positional query]
+ (let [query (query-map query)
+ all-pages? (query "all_pages")
+ req (make-request method end-point positional query)]
+ (http/request req))))
(defn rate-limit [] (api-call :get "rate_limit"))
View
55 src/tentacles/repos.clj
@@ -1,9 +1,10 @@
(ns tentacles.repos
"Implements the Github Repos API: http://developer.github.com/v3/repos/"
(:refer-clojure :exclude [keys])
+ (:require [clojure.data.codec.base64 :as b64])
(:use [clj-http.client :only [post put]]
[clojure.java.io :only [file]]
- [tentacles.core :only [api-call no-content?]]
+ [tentacles.core :only [api-call no-content? raw-api-call]]
[cheshire.core :only [generate-string]]))
;; ## Primary Repos API
@@ -402,4 +403,54 @@
user repo event)
"hub.callback" callback}
(when-let [secret (:secret options)]
- {"hub.secret" secret}))})))
+ {"hub.secret" secret}))})))
+
+;; ## Repo Contents API
+
+(defn- decode-b64
+ "Decodes a base64 encoded string in a response"
+ ([res str? path]
+ (if (and (map? res) (= (:encoding res) "base64"))
+ (if-let [^String encoded (get-in res path)]
+ (let [trimmed (.replace encoded "\n" "")
+ raw (.getBytes trimmed "UTF-8")
+ decoded (b64/decode raw)
+ done (if str? (String. decoded "UTF-8") decoded)]
+ (assoc-in res path done))
+ res)
+ res))
+ ([res str?] (decode-b64 res str? [:content]))
+ ([res] (decode-b64 res false [:content])))
+
+(defn readme
+ "Get the preferred README for a repository.
+ Options are:
+ ref -- The name of the Commit/Branch/Tag. Defaults to master.
+ str? -- Whether the content should be decoded to String. Defaults to true."
+ [user repo {:keys [str?] :or {str? true} :as options}]
+ (decode-b64
+ (api-call :get "repos/%s/%s/readme" [user repo] (dissoc options :str?))
+ str?))
+
+(defn contents
+ "Get the contents of any file or directory in a repository.
+ Options are:
+ ref -- The name of the Commit/Branch/Tag. Defaults to master.
+ str? -- Whether the content should be decoded to a String. Defaults to false (ByteArray)."
+ [user repo path {:keys [str?] :as options}]
+ (decode-b64
+ (api-call :get "repos/%s/%s/contents/%s" [user repo path] (dissoc options :str?))
+ str?))
+
+(defn archive-link
+ "Get a URL to download a tarball or zipball archive for a repository.
+ Options are:
+ ref -- The name of the Commit/Branch/Tag. Defaults to master."
+ ([user repo archive-format {git-ref :ref :or {git-ref ""} :as options}]
+ (let [proper-options (-> options
+ (assoc :follow-redirects false)
+ (dissoc :ref))
+ resp (raw-api-call :get "repos/%s/%s/%s/%s" [user repo archive-format git-ref] proper-options)]
+ (if (= (resp :status) 302)
+ (get-in resp [:headers "location"])
+ resp))))

0 comments on commit 5d5a45d

Please sign in to comment.
Something went wrong with that request. Please try again.