gs

Unnamed repository; edit this file 'description' to name the repository.
git clone git://edryd.org/gs
Log | Files | Refs | LICENSE

commit 19a589165b258cf91cb6140418a2a34e54a60f8f
parent 8be30f8913b1bc963a7a2703eb0fa940849b0912
Author: Ed van Bruggen <edvb54@gmail.com>
Date:   Tue,  1 Aug 2017 23:46:23 -0700

Add -e to edit Gist, -D to delete file from Gist

Diffstat:
README.md | 10+++++++++-
config.def.h | 6++++--
gs.1 | 12++++++++++--
gs.c | 53+++++++++++++++++++++++++++++++++++++++--------------
4 files changed, 62 insertions(+), 19 deletions(-)

diff --git a/README.md b/README.md @@ -2,7 +2,7 @@ ## SYNOPSIS -**gs** [**-pPhv**] [**-d** *DESCRIPTION*] [**-f** *FILENAME*] [**-g** *GITHUB\_URL*] [**-u** *USER*[: *PASSWORD*] | **-U**] [*FILES* ...] +**gs** [**-pPhv**] [**-e** *ID* [**-D** *FILE*]] [**-d** *DESCRIPTION*] [**-f** *FILENAME*] [**-g** *GITHUB\_URL*] [**-u** *USER*[: *PASSWORD*] | **-U**] [*FILES* ...] ## DESCRIPTION @@ -10,10 +10,18 @@ Easy way to create GitHub Gists through the command line. ## OPTIONS +#### -e ID + +Edit previously created Gist specified with *ID* + #### -d DESCRIPTION Set Gist description +#### -D FILE + +Delete *FILE* from Gist being edited + #### -f FILENAME Set file name when reading from `stdin` diff --git a/config.def.h b/config.def.h @@ -1,5 +1,7 @@ -char *desc = ""; /* Gist description */ +char *gist = NULL; /* ID of existing Gist to edit */ +char *desc = NULL; /* Gist description */ +char *del = NULL; /* file name to delete from Gist */ char *fname = NULL; /* Gist filename when reading from stdin */ char *user = NULL; /* GitHub user, password can be given after colon */ -char *ghurl = "https://api.github.com/gists"; /* default GitHub URL to post gists to */ +char *ghurl = "https://api.github.com/gists"; /* GitHub URL to post gists to */ int pub = 1; /* 0: private need link to view, 1: public anyone can find */ diff --git a/gs.1 b/gs.1 @@ -1,22 +1,30 @@ .\" x-roff document .do mso man.tmac -.TH gs 1 "July 2017" "gs 0.0.0" +.TH gs 1 "August 2017" "gs 0.0.0" .PP .SH NAME gs - painless gist creator .PP .SH SYNOPSIS -\fBgs\fP [\fB-pPhv\fP] [\fB-d\fP \fIDESCRIPTION\fP] [\fB-f\fP \fIFILENAME\fP] [\fB-g\fP \fIGITHUB_URL\fP] [\fB-u\fP \fIUSER\fP[:\fIPASSWORD\fP] | \fB-U\fP] [\fIFILES\fP ...] +\fBgs\fP [\fB-pPhv\fP] [\fB-e\fP \fIID\fP [\fB-D\fP \fIFILE\fP] ] [\fB-d\fP \fIDESCRIPTION\fP] [\fB-f\fP \fIFILENAME\fP] [\fB-g\fP \fIGITHUB_URL\fP] [\fB-u\fP \fIUSER\fP[:\fIPASSWORD\fP] | \fB-U\fP] [\fIFILES\fP ...] .PP .SH DESCRIPTION Easy way to create GitHub Gists through the command line. .PP .SH OPTIONS .TP +\fB-e\fP \fIID\fP +\fREdit previously created Gist specified with \fIID\fP +.PP +.TP \fB-d\fP \fIDESCRIPTION\fP \fRSet Gist description .PP .TP +\fB-D\fP \fIFILE\fP +\fRDelete \fIFILE\fP from Gist being edited +.PP +.TP \fB-f\fP \fIFILENAME\fP \fRSet file name when reading from `\f[CR]stdin\fP' .PP diff --git a/gs.c b/gs.c @@ -13,6 +13,7 @@ /* defines */ #define LBUF_SIZE 1024 /* TODO remove BUF_SIZEs */ #define BUF_SIZE 100000 +#define URL_SIZE 2048 /* typedefs */ typedef struct { @@ -22,6 +23,7 @@ typedef struct { /* functions */ static size_t str_write(void *ptr, size_t size, size_t nmemb, Str *s); +static Str http_post(char *content); static char *file_str(FILE *fp); static char *files_js(char *files[], int filec); static void gs_new(char *files[], int filec); @@ -46,9 +48,9 @@ str_write(void *ptr, size_t size, size_t nmemb, Str *s) /* HTTP POST request from content, returning response */ static Str -http_post(char *content, long okcode) +http_post(char *content) { - char *resmsg; + char *resmsg, url[URL_SIZE]; long code; CURL *curl; CURLcode res; @@ -66,7 +68,11 @@ http_post(char *content, long okcode) } /* set cURL options */ - curl_easy_setopt(curl, CURLOPT_URL, ghurl); + if (gist) + snprintf(url, sizeof(url), "%s/%s", ghurl, gist); + else + strcpy(url, ghurl); + curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_USERAGENT, "gs/"VERSION); if (user) { if (strchr(user, ':')) { @@ -76,6 +82,8 @@ http_post(char *content, long okcode) curl_easy_setopt(curl, CURLOPT_PASSWORD, getpass("GitHub password: ")); } } + if (gist) + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH"); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, content); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, str_write); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resstr); @@ -90,7 +98,7 @@ http_post(char *content, long okcode) curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); curl_easy_cleanup(curl); curl_global_cleanup(); - if (code != okcode) { + if (code != (gist ? 200 : 201)) { /* 200 returned when editing gist, 201 when creating */ json_scanf(resstr.ptr, resstr.len, "{message: %Q}", &resmsg); die(-1, "%s: could not create Gist: %s", argv0, resmsg); free(resmsg); @@ -128,20 +136,28 @@ files_js(char *files[], int filec) FILE *fp = stdin; struct json_out jout = JSON_OUT_BUF(js, BUF_SIZE); - if (!desc) - die(1, "%s: description not given", argv0); - json_printf(&jout, "{ description: %Q, public: %B, files: {", desc, pub); + json_printf(&jout, "{ public: %B,", pub); + if (!desc && !gist) /* when creating new Gist, if no description given, make it empty */ + desc = ""; + if (desc) /* only add description as blank if gist is being created */ + json_printf(&jout, "description: %Q, ", desc); + json_printf(&jout, "files: {"); + + if (del) /* delete file if given by setting it to NULL */ + json_printf(&jout, "%Q: %Q", basename(del), NULL); /* add each file */ for (i = 0; !i || i < filec; i++) { - if (i) /* insert comma if this is another file */ - json_printf(&jout, ","); if (filec && !(fp = fopen(files[i], "r"))) die(1, "%s: %s: could not load file", argv0, files[i]); - if (filec) /* set file name if given */ + if (filec) /* set file name if given */ fname = files[i]; - if (!fname) /* check for file name when using stdin */ + if (!fname && gist) /* don't need file if we are editing gist */ + break; + if (!fname) /* check for file name when using stdin */ die(1, "%s: file name not given", argv0); + if (i || del) /* insert comma if this is another file */ + json_printf(&jout, ","); fbuf = file_str(fp); json_printf(&jout, "%Q: { content: %Q }", basename(fname), fbuf); efree(fbuf); @@ -160,7 +176,7 @@ gs_new(char *files[], int filec) js = files_js(files, filec); - resstr = http_post(js, 201); + resstr = http_post(js); json_scanf(resstr.ptr, resstr.len, "{html_url: %Q}", &url); printf("%s\n", url); @@ -174,17 +190,23 @@ gs_new(char *files[], int filec) static void usage(const int eval) { - die(eval, "usage: %s [-pPhv] [-d DESCRIPTION] [-f FILENAME] [-g GITHUB_URL]\n" - " [-u USER[:PASSWORD] | -U] [FILES ...]", argv0); + die(eval, "usage: %s [-pPhv] [-e ID [-D FILE]] [-d DESCRIPTION] [-f FILENAME]\n" + " [-g GITHUB_URL] [-u USER[:PASSWORD] | -U] [FILES ...]", argv0); } int main(int argc, char *argv[]) { ARGBEGIN { + case 'e': + gist = EARGF(usage(1)); + break; case 'd': desc = EARGF(usage(1)); break; + case 'D': + del = EARGF(usage(1)); + break; case 'f': fname = EARGF(usage(1)); break; @@ -212,6 +234,9 @@ main(int argc, char *argv[]) usage(1); } ARGEND; + if (gist && !user) + die(1, "%s: cannot edit Gists without user", argv0); + gs_new(argv, argc); return 0;