aboutsummaryrefslogblamecommitdiff
path: root/src/evanix.c
blob: 80a5b25e3f0bfbc2bca9fc5ecb91b313beebad68 (plain) (tree)
1
2
3
4
5
6
7
8
9
                   

                   
                  
 
                  
                   
                  
                          
                         

                 


                                        


                                                                            
                  

                                                                    
                                                                            



                                                                            
                                                             


                                    
                                


                            
                       
                       
                               
                                   
                                
                              

  
                                                                         

                              

















                                                                            
                             

                                                 
                                                 
                                                           

                    
                                           


                              
                                                          
                      
                                 


                              

                                                                   
                                 


                              

                                                                          





                                                                    
                                               


                              
                                    
                                                               

                                                            
                       
                                               


                              


                                                            

                                                               
                                               



                                                    
                       
                                               




                                        
                           


                   
                                                                              


                                          
                              




                                                    
                                                         
                                                         
                                                         
                                                          
                                                            
                                                            
                                                                  
                                                                     


                                   
                                                                           

                                                     

                                            
                                       

                              



                                                  

                              
                                              
                              
                         
                                              
                              
                         
                                                   
                              

                                                        


                                                              






                                                                           
                                               

                              



                                               
                                                                               


                                                                       
                                           
                                               

                         
                                              
                              



                                               
                                                                               

                                                                       
                                           
                                               

                         
                                                




                                               
                                                                               

                                                                       
                                           
                                               

                         
                                                    
                              



                                               
                                                                               

                                                                       
                                           
                                               

                         
                                                       
                              


                                                                               
                                       





                                                                               


                               







                                                                         

         












                                                         




                                   
 
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include "build.h"
#include "evanix.h"
#include "queue.h"
#include "solver_greedy.h"
#include "solver_highs.h"
#include "util.h"

static const char usage[] =
	"Usage: evanix [options] expr\n"
	"\n"
	"  -h, --help                       Show help message and quit.\n"
	"  -f, --flake                      Build a flake.\n"
	"  -d, --dry-run                    Show what derivations would be "
	"built.\n"
	"  -s, --system                     System to build for.\n"
	"  -m, --max-build                  Max number of builds.\n"
	"  -b, --break-evanix               Enable experimental features.\n"
	"  -r, --solver-report              Print solver report.\n"
	"  -p, --pipelined          <bool>  Use evanix build pipeline.\n"
	"  -l, --check_cache-status <bool>  Perform cache locality check.\n"
	"  -c, --close-unused-fd    <bool>  Close stderr on exec.\n"
	"  -k, --solver       highs|greedy  Solver to use.\n"
	"\n";

struct evanix_opts_t evanix_opts = {
	.close_unused_fd = true,
	.isflake = false,
	.ispipelined = true,
	.isdryrun = false,
	.max_build = 0,
	.system = NULL,
	.solver_report = false,
	.check_cache_status = true,
	.solver = solver_greedy,
	.break_evanix = false,
};

static int evanix_build_thread_create(struct build_thread *build_thread);
static int evanix(char *expr);

/* This function returns errno on failure, consistent with the POSIX threads
 * functions, rather than returning -errno. */
static int evanix_build_thread_create(struct build_thread *build_thread)
{
	int ret;

	ret = pthread_create(&build_thread->tid, NULL, build_thread_entry,
			     build_thread);
	if (ret != 0)
		return ret;

	ret = pthread_setname_np(build_thread->tid, "evanix_build");
	if (ret != 0)
		return ret;

	return 0;
}

static int evanix(char *expr)
{
	struct queue_thread *queue_thread = NULL;
	struct build_thread *build_thread = NULL;
	FILE *jobsStream = NULL; /* nix-eval-jobs stdout */
	int ret = 0;

	ret = jobs_init(&jobsStream, expr);
	if (ret < 0)
		goto out_free;

	ret = queue_thread_new(&queue_thread, jobsStream);
	if (ret < 0) {
		free(jobsStream);
		goto out_free;
	}

	ret = build_thread_new(&build_thread, queue_thread->queue);
	if (ret < 0) {
		free(jobsStream);
		goto out_free;
	}

	ret = pthread_create(&queue_thread->tid, NULL, queue_thread_entry,
			     queue_thread);
	if (ret != 0) {
		print_err("%s", strerror(ret));
		goto out_free;
	}
	ret = pthread_setname_np(queue_thread->tid, "evanix_queue");
	if (ret != 0) {
		print_err("%s", strerror(ret));
		goto out_free;
	}

	if (evanix_opts.ispipelined)
		ret = evanix_build_thread_create(build_thread);
	else
		ret = pthread_join(queue_thread->tid, NULL);
	if (ret != 0) {
		print_err("%s", strerror(ret));
		goto out_free;
	}

	if (evanix_opts.ispipelined)
		ret = pthread_join(queue_thread->tid, NULL);
	else
		ret = evanix_build_thread_create(build_thread);
	if (ret != 0) {
		print_err("%s", strerror(ret));
		goto out_free;
	}

	ret = pthread_join(build_thread->tid, NULL);
	if (ret != 0) {
		print_err("%s", strerror(ret));
		goto out_free;
	}

out_free:
	queue_thread_free(queue_thread);
	free(build_thread);
	return ret;
}

int opts_read(struct evanix_opts_t *opts, char **expr, int argc, char *argv[])
{
	extern int optind, opterr, optopt;
	extern char *optarg;
	int ret, longindex, c;

	static struct option longopts[] = {
		{"help", no_argument, NULL, 'h'},
		{"flake", no_argument, NULL, 'f'},
		{"dry-run", no_argument, NULL, 'd'},
		{"break-evanix", no_argument, NULL, 'b'},
		{"solver", required_argument, NULL, 'k'},
		{"system", required_argument, NULL, 's'},
		{"solver-report", no_argument, NULL, 'r'},
		{"max-build", required_argument, NULL, 'm'},
		{"pipelined", required_argument, NULL, 'p'},
		{"close-unused-fd", required_argument, NULL, 'c'},
		{"check-cache-status", required_argument, NULL, 'l'},
		{NULL, 0, NULL, 0},
	};

	while ((c = getopt_long(argc, argv, "hfds:r::m:p:c:l:k:", longopts,
				&longindex)) != -1) {
		switch (c) {
		case 'h':
			printf("%s", usage);
			return -EINVAL;
			break;
		case 'f':
			opts->isflake = true;
			break;
		case 'b':
			opts->break_evanix = true;
			break;
		case 'd':
			opts->isdryrun = true;
			break;
		case 's':
			opts->system = optarg;
			break;
		case 'r':
			opts->solver_report = true;
			break;
		case 'k':
			if (!strcmp(optarg, "greedy")) {
				opts->solver = solver_greedy;
			} else if (!strcmp(optarg, "highs")) {
				opts->solver = solver_highs;
			} else {
				fprintf(stderr,
					"option -%c has an invalid solver "
					"argument\n"
					"Try 'evanix --help' for more "
					"information.\n",
					c);
				return -EINVAL;
			}
			break;
		case 'm':
			ret = atoi(optarg);
			if (ret <= 0) {
				fprintf(stderr,
					"option -%c requires a natural number "
					"argument\n"
					"Try 'evanix --help' for more "
					"information.\n",
					c);
				return -EINVAL;
			}

			opts->max_build = ret;
			break;
		case 'p':
			ret = atob(optarg);
			if (ret < 0) {
				fprintf(stderr,
					"option -%c requires a bool argument\n"
					"Try 'evanix --help' for more "
					"information.\n",
					c);
				return -EINVAL;
			}

			opts->ispipelined = ret;
			break;
		case 'c':
			ret = atob(optarg);
			if (ret < 0) {
				fprintf(stderr,
					"option -%c requires a bool argument\n"
					"Try 'evanix --help' for more "
					"information.\n",
					c);
				return -EINVAL;
			}

			opts->close_unused_fd = ret;
			break;
		case 'l':
			ret = atob(optarg);
			if (ret < 0) {
				fprintf(stderr,
					"option -%c requires a bool argument\n"
					"Try 'evanix --help' for more "
					"information.\n",
					c);
				return -EINVAL;
			}

			opts->check_cache_status = ret;
			break;
		default:
			fprintf(stderr,
				"Try 'evanix --help' for more information.\n");
			return -EINVAL;
			break;
		}
	}
	if (optind != argc - 1) {
		fprintf(stderr, "evanix: invalid expr operand\n"
				"Try 'evanix --help' for more information.\n");
		return -EINVAL;
	}

	if (opts->solver == solver_highs) {
		if (opts->break_evanix == false) {
			fprintf(stderr, "Running --solver=highs without "
					"--break-evanix\n");
			return -EINVAL;
		}

		opts->ispipelined = false;
	}

	*expr = argv[optind];
	return 0;
}

int main(int argc, char *argv[])
{
	char *expr;
	int ret;

	ret = opts_read(&evanix_opts, &expr, argc, argv);
	if (ret < 0)
		exit(EXIT_FAILURE);

	ret = evanix(argv[optind]);
	if (ret < 0)
		exit(EXIT_FAILURE);

	exit(EXIT_SUCCESS);
}