diff --git a/Readme.md b/Readme.md index 8a5b645..dcf2740 100644 --- a/Readme.md +++ b/Readme.md @@ -16,13 +16,14 @@ Tested on Linux and Windows 64 bits. ## Examples -* [Git Init](./examples/init): `shows how to initialize a new repo` -* [Git Status](./examples/status): `shows how to use the status APIs` +* [Git Init](./examples/init) `shows how to initialize a new repo` +* [Git Status](./examples/status) `shows how to use the status APIs` * [Git Add](./examples/add) `shows how to modify the index` * [Git Checkout](./examples/checkout) `shows how to perform checkouts`. * [Git Describe](./examples/describe) `shows how to describe commits`. * [Git ls-files](./examples/ls_files) `shows how to view all files currently in the index.` -* [Git push](./examples/push) `shows how to git push `. +* [Git push](./examples/push) `shows how to git push ` +* [Git ls_remote](./examples/ls_remote) `shows how to list remote references.` [Guide to linking libgit2](https://libgit2.org/docs/guides/build-and-link/) on various platforms diff --git a/examples/ls_remote/application.e b/examples/ls_remote/application.e new file mode 100644 index 0000000..2711b1f --- /dev/null +++ b/examples/ls_remote/application.e @@ -0,0 +1,279 @@ +note + description: "[ + libgit2 "ls_remote" example - shows how to list remote references + ]" + +class APPLICATION + +inherit + + COMMAND_LINE_PARSER + rename + make as make_command_line_parser + end + +create + make + +feature {NONE} --Initialization + + make + + do + create git_repository + path := "." + remote := "" + + make_command_line_parser + process_arguments + show_remote + end + + +feature -- Intiialize Repository + + show_remote + local + ini: INTEGER + repo: GIT_REPOSITORY_STRUCT_API + iniopts: GIT_REPOSITORY_INIT_OPTIONS_STRUCT_API + l_remote: GIT_REMOTE_STRUCT_API + git_remote: GIT_REMOTE + refspec: STRING + l_options: GIT_PUSH_OPTIONS_STRUCT_API + a_array: GIT_STRARRAY_STRUCT_API + callbacks: GIT_REMOTE_CALLBACKS_STRUCT_API + callback_dispatcher: GIT_CRED_ACQUIRE_CB_DISPATCHER + refs: ARRAYED_LIST [GIT_REMOTE_HEAD_STRUCT_API] + ref_len: INTEGER + git_oid: GIT_OID + oid: STRING + + do + ini := {LIBGIT2_INITIALIZER_API}.git_libgit2_init + print ("%NIntializing Libgit2") + create repo.make + + if git_repository.git_repository_open (repo, (create {PATH}.make_from_string (path)).out) < 0 then + print ("%NCould not open repository") + {EXCEPTIONS}.die (1) + end + + -- get the remote + create l_remote.make + + create git_remote + if git_remote.git_remote_lookup (l_remote, repo, remote) < 0 then + if git_remote.git_remote_create_anonymous (l_remote, repo, remote) < 0 then + print ("%NCould not get remote repository " + remote) + {EXCEPTIONS}.die (1) + end + end + + create callbacks.make + if git_remote.git_remote_init_callbacks (callbacks, 1) < 0 then + print ("%NCould not intialize callback ") + {EXCEPTIONS}.die (1) + end + + create callback_dispatcher.make (agent cred_acquire_cb ) + callbacks.set_credentials (callback_dispatcher.c_dispatcher) + + -- connect to remote + if git_remote.git_remote_connect (l_remote, {GIT_DIRECTION_ENUM_API}.git_direction_fetch, callbacks, Void, Void) < 0 then + print ("%NCould not connect to remote repository " + remote) + {EXCEPTIONS}.die (1) + end + + create refs.make (1) + -- Get the list of references on the remote and print out + -- their name next to what they point to. + + if git_remote.git_remote_ls (refs, l_remote) < 0 then + print ("%NCould not get the remote repository's reference advertisement list") + {EXCEPTIONS}.die (1) + end + + create git_oid + from + refs.start + until + refs.after + loop + create oid.make ({LIBGIT2_CONSTANTS}.GIT_OID_HEXSZ + 1) + if attached refs.item_for_iteration.oid as l_oid then + git_oid.git_oid_fmt (oid, l_oid) + if attached refs.item_for_iteration.name as l_name then + print("%N" + oid.substring (1, {LIBGIT2_CONSTANTS}.GIT_OID_HEXSZ) +"%T" + l_name ) + else + print("%N" + oid +"%T") + end + end + refs.forth + + end + git_repository.git_repository_free (repo) + git_remote.git_remote_free (l_remote) + ini := {LIBGIT2_INITIALIZER_API}.git_libgit2_shutdown + io.read_line + end + + init_array (a_array: GIT_STRARRAY_STRUCT_API; l_array: ARRAY [STRING]) + local + mp: MANAGED_POINTER + do + create mp.make (l_array.count * {PLATFORM}.pointer_bytes) + across l_array as ic loop + mp.put_pointer ((create {C_STRING}.make (ic.item)).item, (ic.cursor_index - 1) * {PLATFORM}.pointer_bytes ) + end + a_array.set_count (l_array.count) + a_array.set_strings (mp.item) + end + + cred_acquire_cb (a_cred: POINTER; a_url: POINTER; a_username_from_url: POINTER; a_allowed_types: INTEGER; a_payload: POINTER): INTEGER + local + l_user_name: STRING + exit: BOOLEAN + cred: GIT_CRED_STRUCT_API + git_cred: GIT_CREDENTIALS_API + l_password: STRING + l_privkey: STRING + l_pubkey: STRING + do + + if a_username_from_url /= default_pointer then + l_user_name := (create {C_STRING}.make_by_pointer (a_username_from_url)).string + exit := l_user_name.is_empty + else + print ("%NUsername:") + io.read_line + l_user_name := io.last_string.twin + exit := l_user_name.is_empty + end + + if not exit and then a_allowed_types & {GIT_CREDTYPE_T_ENUM_API}.GIT_CREDTYPE_SSH_KEY > 0 then + print ("%NSSH key:") + io.read_line + l_privkey := io.last_string.twin + print ("%NPassword:") + l_password := read_password + if l_password.is_empty or l_privkey.is_empty then + exit := True + end + create l_pubkey.make_from_string (l_password) + l_pubkey.append_string (".pub") + create git_cred + create cred.make_by_pointer (a_cred) + Result := git_cred.git_cred_ssh_key_new(cred, l_user_name, l_pubkey, l_privkey, l_password) + elseif not exit and then a_allowed_types & {GIT_CREDTYPE_T_ENUM_API}.GIT_CREDTYPE_USERPASS_PLAINTEXT > 0 then + print ("%NPassword:") + l_password := read_password + exit := l_password.is_empty + if not exit then + create git_cred + create cred.make_by_pointer (a_cred) + Result := git_cred.git_cred_userpass_plaintext_new(cred, l_user_name, l_password) + end + else + if not exit then + create git_cred + create cred.make_by_pointer (a_cred) + Result := git_cred.git_cred_username_new (cred, l_user_name) + end + end + + end + +feature {NONE} -- Process Arguments + + process_arguments + -- Process command line arguments + local + shared_value: STRING + do + if match_long_option ("git-dir") then + if is_next_option_long_option and then has_next_option_value then + create path.make_from_string (next_option_value) + consume_option + else + print("%N Missing command line parameter --git-dir=") + usage + {EXCEPTIONS}.die (1) + end + end + if has_next_option and then not is_next_option_long_option then + create remote.make_from_string (next_option) + consume_option + else + print("%N Missing command line parameter %N") + usage + {EXCEPTIONS}.die (1) + end + end + + usage + local + str: STRING + do + str := "[ + lxs [--git-dir=] + + ]" + + print("%N") + print (str) + end + + read_password: STRING + local + l_ptr: POINTER + do + l_ptr := c_read_password + if l_ptr /= default_pointer then + Result := (create {C_STRING}.make_by_pointer (l_ptr)).string + else + Result := "" + end + end + + c_read_password: POINTER + external "C inline" + alias + "[ + #define ENTER 13 + #define TAB 9 + #define BKSP 8 + + char* pwd; + + int i = 0; + char ch; + + while(1){ + ch = getch(); //get key + + if(ch == ENTER || ch == TAB){ + pwd[i] = '\0'; + break; + }else if(ch == BKSP){ + if(i > 0){ + i--; + printf("\b \b"); //for backspace + } + }else{ + pwd[i++] = ch; + printf("* \b"); //to replace password character with * + } + }//while ends here + + return pwd; + ]" + end + +feature -- Options + + path: STRING + remote: STRING + git_repository: LIBGIT2_REPOSITORY + +end diff --git a/examples/ls_remote/command_line_parser.e b/examples/ls_remote/command_line_parser.e new file mode 100644 index 0000000..772932b --- /dev/null +++ b/examples/ls_remote/command_line_parser.e @@ -0,0 +1,174 @@ +note + description: "Summary description for {COMMAND_LINE_PARSER}." + date: "$Date$" + revision: "$Revision$" + +class + COMMAND_LINE_PARSER + +inherit + + ARGUMENTS_32 + +create + make + + +feature {NONE} -- Initialization + + make + -- Create a new command-line parser. + do + reset + end + +feature -- Operations + + reset + -- Reset internal option position to first option + -- must be called before first use. + do + next_option_position := 1 + end + + consume_option + -- Move `next_token_position' to the next token position. + do + next_option_position := next_option_position + 1 + end + +feature -- Status report + + has_next_option: BOOLEAN + -- Is there an unconsumed token left? + do + Result := is_valid_option_position (next_option_position) + end + + is_next_option_long_option: BOOLEAN + -- Is the next option a long option (with or without a value)? + local + arg: STRING_32 + do + if has_next_option then + arg := next_option.as_string_32 + Result := arg.count >= 2 and then + arg.substring (1, 2).same_string ("--") + end + end + + has_next_option_value: BOOLEAN + -- Has the next option a value? + require + has_next_option: has_next_option + next_option_is_long_option: is_next_option_long_option + local + i: INTEGER + arg: STRING_32 + do + arg := next_option.as_string_32 + i := arg.index_of ('=', 1) + Result := (i >= 1 and i < arg.count) + end + +feature -- Access + + next_option: STRING_32 + -- Next option on command-line + require + has_next_option: has_next_option + do + Result := argument (next_option_position).as_string_32 + ensure + next_option_not_void: Result /= Void + end + + next_option_value: STRING_32 + -- Value of next option + require + next_option_is_long_option: is_next_option_long_option + has_next_option_value: has_next_option_value + local + i: INTEGER + arg: STRING_32 + do + arg := next_option.as_string_32 + i := arg.index_of ('=', 1) + Result := arg.substring (i + 1, arg.count) + ensure + next_option_value_not_void: Result /= Void + end + +feature -- Matching + + match_long_option (an_option_name: STRING): BOOLEAN + -- Is there a next option on the command-line and + -- is this option a long option whose name is + -- `an_option_name' (Note that `an_option_name' + -- does not contain the leading '--' characters)? + require + an_option_name_not_void: an_option_name /= Void + local + arg: STRING_32 + nb: INTEGER + do + if has_next_option then + arg := next_option.as_string_32 + nb := an_option_name.count + 2 + if + arg.count >= nb and then + (arg.item (1) = '-' and + arg.item (2) = '-') and then + arg.substring (3, nb).same_string (an_option_name) + then + Result := (arg.count = nb or else arg.item (nb + 1) = '=') + end + end + end + +feature {NONE} -- Implementation + + next_option_position: INTEGER + -- Index of next option + + is_valid_option_position (i: INTEGER): BOOLEAN + -- Is `i' a valid token position? + do + Result := (i >= 1 and i <= argument_count) + end + +feature -- Status report + + has_long_option (an_option_name: STRING): BOOLEAN + -- Is there a long option on the command-line whose name is + -- `an_option_name' (note that `an_option_name' does not + -- contain the leading '--' characters)? + require + an_option_name_not_void: an_option_name /= Void + local + i: INTEGER + arg: STRING_32 + nb: INTEGER + do + from + i := 1 + until + (i > argument_count) or Result + loop + arg := argument (i).as_string_32 + nb := an_option_name.count + 2 + if + arg.count >= nb and then + (arg.item (1) = '-' and + arg.item (2) = '-') and then + arg.substring (3, nb).same_string (an_option_name) + then + Result := (arg.count = nb or else arg.item (nb + 1) = '=') + end + + i := i + 1 + end + end + +end + diff --git a/examples/ls_remote/ls_remote.ecf b/examples/ls_remote/ls_remote.ecf new file mode 100644 index 0000000..f6ead8c --- /dev/null +++ b/examples/ls_remote/ls_remote.ecf @@ -0,0 +1,20 @@ + + + + + + /CVS$ + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + + + diff --git a/library/generated_wrapper/eiffel/git_oid.e b/library/manual_wrapper/git_oid.e similarity index 57% rename from library/generated_wrapper/eiffel/git_oid.e rename to library/manual_wrapper/git_oid.e index 31b1b48..77825d5 100644 --- a/library/generated_wrapper/eiffel/git_oid.e +++ b/library/manual_wrapper/git_oid.e @@ -10,7 +10,8 @@ inherit GIT_OID_API rename - git_oid_fromstr as git_oid_fromstr_api + git_oid_fromstr as git_oid_fromstr_api, + git_oid_fmt as git_oid_fmt_api end @@ -25,4 +26,14 @@ feature -- Access Result := c_git_oid_fromstr (a_out.item, str_c_string.item) end + git_oid_fmt (a_out: STRING; id: GIT_OID_STRUCT_API) + local + a_out_c_string: C_STRING + do + create a_out_c_string.make (a_out) + c_git_oid_fmt (a_out_c_string.item, id.item) + a_out.from_c (a_out_c_string.item) + end + + end diff --git a/library/manual_wrapper/git_remote.e b/library/manual_wrapper/git_remote.e index 09e592e..b27e620 100644 --- a/library/manual_wrapper/git_remote.e +++ b/library/manual_wrapper/git_remote.e @@ -11,7 +11,9 @@ inherit GIT_REMOTE_API rename git_remote_lookup as git_remote_lookup_api, - git_remote_connect as git_remote_connect_api + git_remote_connect as git_remote_connect_api, + git_remote_create_anonymous as git_remote_create_anonymous_api, + git_remote_ls as git_remote_ls_api end @@ -29,6 +31,19 @@ feature -- Access end end + git_remote_create_anonymous (a_out: GIT_REMOTE_STRUCT_API; repo: GIT_REPOSITORY_STRUCT_API; url: STRING): INTEGER + local + url_c_string: C_STRING + l_ptr: POINTER + do + create url_c_string.make (url) + Result := c_git_remote_create_anonymous ($l_ptr, repo.item, url_c_string.item) + if l_ptr /= default_pointer then + a_out.make_by_pointer (l_ptr) + end + + end + git_remote_connect (remote: GIT_REMOTE_STRUCT_API; direction: INTEGER; callbacks: detachable GIT_REMOTE_CALLBACKS_STRUCT_API; proxy_opts: detachable GIT_PROXY_OPTIONS_STRUCT_API; custom_headers: detachable GIT_STRARRAY_STRUCT_API): INTEGER local l_callbacks: POINTER @@ -47,5 +62,34 @@ feature -- Access Result := c_git_remote_connect (remote.item, direction, l_callbacks, l_proxy_opts, l_custom_header) end + git_remote_ls (a_out: LIST [GIT_REMOTE_HEAD_STRUCT_API]; remote: GIT_REMOTE_STRUCT_API): INTEGER + local + l_ptr: POINTER + l_mgr: MANAGED_POINTER + i: INTEGER + l_size: INTEGER + l_item: POINTER + l_remote: GIT_REMOTE_HEAD_STRUCT_API + do + create l_remote.make + l_ptr := l_remote.item + Result := c_git_remote_ls ($l_ptr, $l_size, remote.item) + if l_ptr /= default_pointer then + create l_mgr.make_from_pointer (l_ptr, l_size * {PLATFORM}.pointer_bytes) + from + i := 0 + until + i = l_mgr.count + loop + l_item := l_mgr.read_pointer (i) + if l_item /= default_pointer then + a_out.force (create {GIT_REMOTE_HEAD_STRUCT_API}.make_by_pointer (l_item)) + end + i := i + {PLATFORM}.pointer_bytes + end + + end + end + end diff --git a/library/manual_wrapper/libgit2_constants.e b/library/manual_wrapper/libgit2_constants.e index c3b5c36..94ae532 100644 --- a/library/manual_wrapper/libgit2_constants.e +++ b/library/manual_wrapper/libgit2_constants.e @@ -17,4 +17,24 @@ feature -- Access is_class: class end + + GIT_OID_HEXSZ: INTEGER + external + "C inline use " + alias + "GIT_OID_HEXSZ" + end + + +-- /** Size (in bytes) of a raw/binary oid */ +--#define GIT_OID_RAWSZ 20 + +--/** Size (in bytes) of a hex formatted oid */ +--#define GIT_OID_HEXSZ (GIT_OID_RAWSZ * 2) + +--/** Minimum length (in number of hex characters, +-- * i.e. packets of 4 bits) of an oid prefix */ +--#define GIT_OID_MINPREFIXLEN 4 + + end