diff --git a/include/noun/manage.h b/include/noun/manage.h index 1bdd04aa1..63fc71bd9 100644 --- a/include/noun/manage.h +++ b/include/noun/manage.h @@ -7,7 +7,7 @@ /* u3m_boot(): start the u3 system. */ void - u3m_boot(c3_o nuu_o, c3_o bug_o, c3_c* dir_c, c3_c *pil_c, c3_c *url_c); + u3m_boot(c3_o nuu_o, c3_o bug_o, c3_c* dir_c, c3_c *pil_c, c3_c *url_c, c3_c *arv_c); /* u3m_bail(): bail out. Does not return. ** diff --git a/include/vere/vere.h b/include/vere/vere.h index 79f13c52c..f1ad36103 100644 --- a/include/vere/vere.h +++ b/include/vere/vere.h @@ -537,7 +537,7 @@ c3_c* pil_c; // -B, bootstrap from c3_c* raf_c; // -r, raft flotilla c3_c* tic_c; // -t, ticket value - c3_c* url_c; // -u, pill url + c3_c* url_c; // -u, pill url c3_c* who_c; // -w, begin with ticket c3_o abo; // -a c3_o bat; // -b, batch create @@ -546,6 +546,7 @@ c3_o fak; // -F, fake carrier c3_o fog; // -X, skip last event c3_o gab; // -g, run with garbage collector + c3_o git; // -s, pill url from arvo git hash c3_o loh; // -L, local-only networking c3_o mem; // -M, memory madness c3_o nuu; // -c, new pier diff --git a/noun/manage.c b/noun/manage.c index 9405dd1f3..92b940506 100644 --- a/noun/manage.c +++ b/noun/manage.c @@ -1500,9 +1500,81 @@ _cm_init(c3_o chk_o) } } +/* _get_cmd_output(): Run a shell command and capture its output. + Exits with an error if the command fails or produces no output. + The 'out_c' parameter should be an array of sufficient length to hold + the command's output, up to a max of 2048 characters. +*/ +static void +_get_cmd_output(c3_c *cmd_c, c3_c *out_c) +{ + FILE *fp = popen(cmd_c, "r"); + if ( NULL == fp ) { + fprintf(stderr, "'%s' failed\n", cmd_c); + exit(1); + } + + if ( NULL == fgets(out_c, 2048, fp) ) { + fprintf(stderr, "'%s' produced no output\n", cmd_c); + exit(1); + } + + pclose(fp); +} + +/* _arvo_hash(): retrieve git hash of arvo directory. + hax_c must be an array with length >= 41. +*/ +static void +_arvo_hash(c3_c *out_c, c3_c *arv_c) +{ + c3_c cmd_c[2048]; + + sprintf(cmd_c, "git -C %s rev-parse HEAD", arv_c); + _get_cmd_output(cmd_c, out_c); + + out_c[strcspn(out_c, "\r\n")] = 0; /* strip newline */ +} + +/* _git_branch(): retrieve the current git branch */ +static void +_git_branch(c3_c *out_c, c3_c *arv_c) +{ + c3_c cmd_c[2048]; + + sprintf(cmd_c, "git -C %s rev-parse --abbrev-ref HEAD", arv_c); + _get_cmd_output(cmd_c, out_c); + + out_c[strcspn(out_c, "\r\n")] = 0; /* strip newline */ +} + +/* _git_pill_url(): produce a URL from which to download a pill + based on the location of an arvo git repository. +*/ +static void +_git_pill_url(c3_c *out_c, c3_c *arv_c) +{ + assert(NULL != arv_c); + + if ( 0 != system("which git >> /dev/null") ) { + fprintf(stderr, "Could not find git executable\n"); + exit(1); + } + + { + c3_c hax_c[2048]; + c3_c bra_c[2048]; + + _git_branch(bra_c, arv_c); + _arvo_hash(hax_c, arv_c); + + sprintf(out_c, "https://bootstrap.urbit.org/%s-%s.pill", hax_c, bra_c); + } +} + /* _boot_home(): create ship directory. */ static void -_boot_home(c3_c *dir_c, c3_c *pil_c, c3_c *url_c) +_boot_home(c3_c *dir_c, c3_c *pil_c, c3_c *url_c, c3_c *arv_c) { c3_c ful_c[2048]; @@ -1522,7 +1594,6 @@ _boot_home(c3_c *dir_c, c3_c *pil_c, c3_c *url_c) snprintf(ful_c, 2048, "%s/.urb/sis", dir_c); mkdir(ful_c, 0700); } - /* Copy urbit.pill. */ { { @@ -1534,6 +1605,8 @@ _boot_home(c3_c *dir_c, c3_c *pil_c, c3_c *url_c) return; } } + + /* Copy local pill file. */ if ( pil_c != 0 ) { snprintf(ful_c, 2048, "cp %s %s/.urb/urbit.pill", pil_c, dir_c); @@ -1542,10 +1615,19 @@ _boot_home(c3_c *dir_c, c3_c *pil_c, c3_c *url_c) fprintf(stderr, "could not %s\n", ful_c); exit(1); } - } else { + } + /* Fetch remote pill over HTTP. */ + else { CURL *curl; CURLcode result; FILE *file; + c3_c pil_c[2048]; + + /* use arvo git hash and branch for pill url unless overridden */ + if ( NULL == url_c ) { + url_c = pil_c; + _git_pill_url(url_c, arv_c); + } snprintf(ful_c, 2048, "%s/.urb/urbit.pill", dir_c); printf("fetching %s to %s\r\n", url_c, ful_c); @@ -1562,8 +1644,10 @@ _boot_home(c3_c *dir_c, c3_c *pil_c, c3_c *url_c) result = curl_easy_perform(curl); fclose(file); if ( result != CURLE_OK ) { - fprintf(stderr, "failed to fetch %s: %s\n", url_c, curl_easy_strerror(result)); - fprintf(stderr, "please fetch it manually and specify the location with -B\n"); + fprintf(stderr, "failed to fetch %s: %s\n", + url_c, curl_easy_strerror(result)); + fprintf(stderr, + "please fetch it manually and specify the location with -B\n"); exit(1); } curl_easy_cleanup(curl); @@ -1574,7 +1658,8 @@ _boot_home(c3_c *dir_c, c3_c *pil_c, c3_c *url_c) /* u3m_boot(): start the u3 system. */ void -u3m_boot(c3_o nuu_o, c3_o bug_o, c3_c* dir_c, c3_c *pil_c, c3_c *url_c) +u3m_boot(c3_o nuu_o, c3_o bug_o, c3_c* dir_c, + c3_c *pil_c, c3_c *url_c, c3_c *arv_c) { /* Activate the loom. */ @@ -1601,7 +1686,7 @@ u3m_boot(c3_o nuu_o, c3_o bug_o, c3_c* dir_c, c3_c *pil_c, c3_c *url_c) if ( _(nuu_o) ) { c3_c ful_c[2048]; - _boot_home(dir_c, pil_c, url_c); + _boot_home(dir_c, pil_c, url_c, arv_c); snprintf(ful_c, 2048, "%s/.urb/urbit.pill", dir_c); diff --git a/vere/main.c b/vere/main.c index 2172d042b..10562b938 100644 --- a/vere/main.c +++ b/vere/main.c @@ -72,6 +72,7 @@ _main_getopt(c3_i argc, c3_c** argv) u3_Host.ops_u.fak = c3n; u3_Host.ops_u.fog = c3n; u3_Host.ops_u.gab = c3n; + u3_Host.ops_u.git = c3n; u3_Host.ops_u.loh = c3n; u3_Host.ops_u.mem = c3n; u3_Host.ops_u.nuu = c3n; @@ -82,7 +83,7 @@ _main_getopt(c3_i argc, c3_c** argv) u3_Host.ops_u.veb = c3n; u3_Host.ops_u.kno_w = DefaultKernel; - while ( (ch_i=getopt(argc, argv,"G:B:A:I:w:u:t:f:k:l:n:p:r:LabcdgqvxFMPDXR")) != -1 ) { + while ( (ch_i=getopt(argc, argv,"G:B:A:I:w:u:t:f:k:l:n:p:r:LabcdgqsvxFMPDXR")) != -1 ) { switch ( ch_i ) { case 'M': { u3_Host.ops_u.mem = c3y; @@ -176,6 +177,7 @@ _main_getopt(c3_i argc, c3_c** argv) case 'D': { u3_Host.ops_u.dry = c3y; break; } case 'q': { u3_Host.ops_u.qui = c3y; break; } case 'v': { u3_Host.ops_u.veb = c3y; break; } + case 's': { u3_Host.ops_u.git = c3y; break; } case '?': default: { return c3n; } @@ -230,11 +232,22 @@ _main_getopt(c3_i argc, c3_c** argv) return c3n; } - if ( u3_Host.ops_u.nuu != c3y && u3_Host.ops_u.url_c != 0) { + if ( u3_Host.ops_u.nuu != c3y && u3_Host.ops_u.url_c != 0 ) { fprintf(stderr, "-u only makes sense when bootstrapping a new instance\n"); return c3n; - } else if ( u3_Host.ops_u.nuu == c3y && u3_Host.ops_u.url_c == 0 ) { + + } else if ( u3_Host.ops_u.nuu == c3y + && u3_Host.ops_u.url_c == 0 + && u3_Host.ops_u.git == c3n ) { + u3_Host.ops_u.url_c = "https://bootstrap.urbit.org/latest.pill"; + + } else if ( u3_Host.ops_u.nuu == c3y + && u3_Host.ops_u.url_c == 0 + && u3_Host.ops_u.arv_c == 0 ) { + + fprintf(stderr, "-s only makes sense with -A\n"); + return c3n; } if ( u3_Host.ops_u.pil_c != 0 ) { @@ -312,6 +325,7 @@ u3_ve_usage(c3_i argc, c3_c** argv) "-q Quiet\n", "-r host Initial peer address\n", "-R Report urbit build info\n", + "-s Pill URL from arvo git hash\n", "-t ticket Use ~ticket automatically\n", "-u url URL from which to download pill\n", "-v Verbose\n", @@ -566,7 +580,8 @@ main(c3_i argc, u3_Host.ops_u.gab, u3_Host.dir_c, u3_Host.ops_u.pil_c, - u3_Host.ops_u.url_c); + u3_Host.ops_u.url_c, + u3_Host.ops_u.arv_c); /* Start Arvo. */