ocaml-bitbucket / api.ml

open Printf
open Common
open Tiny_json
open Meta_conv.Open
open Json_conv
open Ocaml_conv

open Meta_conv.Types.Result.Open

(* field of type Json.t mc_leftovers is automatically handled for Json, but not for ocaml *)
type 'target mc_leftovers = (string * 'target) list with conv(ocaml)
(* CR jfuruse: mc_fields should be supported in Ocaml_conv *)
type 'target mc_fields = (string * 'target) list with conv(ocaml)

module Json = struct
  include Json
  let ocaml_of_t j = Ocaml.String (Json.show j)
  let t_of_ocaml = function
    | Ocaml.String s -> `Ok (Json.parse s)
    | _ -> assert false
end

module Scheme = struct
  type t = Hg(:"hg":) | Git(:"git":) with conv(json), conv(ocaml)
end

module LocalTime = struct
  type t = string with conv(json), conv(ocaml)
end

module UTCTime = struct
  type t = string with conv(json), conv(ocaml)
end

module Error = struct
  open Format

  let wrap_json_conv = function
    | `Ok v -> `Ok v
    | `Error e -> `Error (`Json_conv e)

  let format ppf = function
    | `Http (n, _err) -> fprintf ppf "HTTP Error %d@." n
    | `Json_conv ((_,v) as e) -> 
        Format.eprintf "%a@.Error input: %s@." 
          (Meta_conv.Types.Error.format (fun _ _ -> ())) e
          (Json.show v)
    | `Json_parse exn -> fprintf ppf "Error at Json parse: %s@." (Printexc.to_string exn)
    | `Other exn -> fprintf ppf "Error: %s@." (Printexc.to_string exn)
end

let curl_get_and_parse convf curlf = 
  Curl.get_string curlf |> Curl.ok200 >>= fun s ->
  (try `Ok (Json.parse s) with e -> `Error (`Json_parse e)) >>= fun j ->
  convf j |> Error.wrap_json_conv

module Data = struct

  (* CR jfuruse: It seems we should use classes since there are so many name overloads *)
    
  (** Full repository information *)
  module Repository = struct
    type t = <
      name              : string;
      scm               : Scheme.t;
      has_wiki          : bool;
      last_updated      : LocalTime.t;
      utc_last_updated  : UTCTime.t;
      created_on        : LocalTime.t;
      utc_created_on    : UTCTime.t;
      owner             : string;
      logo              : string;
      email_mailinglist : string option;
      is_mq             : bool;
      size              : int;
      read_only         : bool;
      followers_count   : int;
      state             : string; (* "str(available)" *)
      website           : string option;
      description       : string option;
      has_issues        : bool;
      is_fork           : bool;
      slug              : string;
      is_private        : bool;
      language          : string;
      email_writers     : bool;
      no_public_forks   : bool;
      resource_uri      : string;
      fork_of           : t option;
      mq_of             : t option;
      creator           : string option;
    > with conv(json), conv(ocaml)
  end

  (** Commited file *)  
  module File = struct
    type t = <
      type_ as "type" : string;
      file : string;
    > with conv(json), conv(ocaml)
  end

  (** Branch info *)    
  module Branch = struct

    type t = <
      node         : string;
      raw_node     : string;
      author       : string;
      raw_author   : string;
      utctimestamp : UTCTime.t;
      timestamp    : LocalTime.t;
      message      : string;
      files        : File.t list;
      size         : int64;
      revision     : int64;
      parents      : string list;
      branch       : string;
      unknown      : Json.t mc_leftovers;
    > with conv(json), conv(ocaml)

  end

  (** User identity info *)
  module UserID = struct
    type t = <
      username     : string;
      display_name : string;
      first_name   : string;
      last_name    : string;
      is_team      : bool;
      avatar       : string;
      resource_uri : string;
      user_rest    : Json.t mc_leftovers;
    > with conv(json), conv(ocaml)
  end

  module User = struct
    type t = <
      user : UserID.t;
      repositories : Repository.t list;
      rest : Json.t mc_leftovers;
    > with conv(json), conv(ocaml)
  end

  module UserRepo = struct

    (** Small version of Repository.t *)  
    type t = <
      owner      : string;
      scm        : Scheme.t;
      slug       : string;
      is_private : bool;
      name       : string
    >

    and ts = t list with conv(json)
  end

end

(** repositories Endpoint *)
module Repositories = struct

  (* https://api.bitbucket.org/1.0/repositories/{accountname}/{repo_slug}/branches *)
  module Branches = struct

    type t = Data.Branch.t mc_fields with conv(json), conv(ocaml)

    let get ~accountname ~repo_slug = 
      Format.eprintf "%s : %s...@." accountname repo_slug;
      curl_get_and_parse 
        t_of_json
        (fun h ->
          (* ~user ~password  *)
          (* h#set_userpwd (Printf.sprintf "%s:%s" user password)) *)
          h#set_url (sprintf "https://api.bitbucket.org/1.0/repositories/%s/%s/branches" accountname repo_slug)
          (* h#set_userpwd (Printf.sprintf "%s:%s" user password) *) )
  end
end

(** user Endpoint *)
module User = struct

  let get ~user ~password = 
    curl_get_and_parse
      Data.User.t_of_json
      (fun h ->
        h#set_url "https://api.bitbucket.org/1.0/user";
        h#set_userpwd (Printf.sprintf "%s:%s" user password))

  module Repositories = struct

    let get ~user ~password = 
      curl_get_and_parse
        Data.UserRepo.ts_of_json
        (fun h ->
          h#set_url "https://api.bitbucket.org/1.0/user/repositories/";
          h#set_userpwd (Printf.sprintf "%s:%s" user password))
  end

end
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.