def test_validate(self):
        validation = validate(self.experiment)
        self.assertTrue(validation)

        # Create temporary directory and test invalid config.json
        broken_experiment = "%s/broken_experiment" % self.tmpdir
        copy_directory(self.experiment, broken_experiment)

        # Missing file specified
        shutil.copyfile("%s/experiment.js" % broken_experiment,
                        "%s/pizza.js" % broken_experiment)
        os.remove("%s/experiment.js" % broken_experiment)
        self.assertFalse(validate(broken_experiment))
        shutil.copyfile("%s/pizza.js" % broken_experiment,
                        "%s/experiment.js" % broken_experiment)

        # Invalid field for template
        broken_config = self.config[:]
        broken_config[0]["template"] = "invalid_framework"
        self.save_config(broken_config, broken_experiment)
        self.assertFalse(validate(broken_experiment))

        # Missing required field
        broken_config = self.config[:]
        del broken_config[0]["exp_id"]
        self.save_config(broken_config, broken_experiment)
        self.assertFalse(validate(broken_experiment))
    def test_validate(self):
        validation = validate(self.experiment)
        self.assertTrue(validation)

        # Create temporary directory and test invalid config.json
        broken_experiment = "%s/broken_experiment" %self.tmpdir
        copy_directory(self.experiment,broken_experiment)

        # Missing file specified
        shutil.copyfile("%s/experiment.js" %broken_experiment,"%s/pizza.js" %broken_experiment)
        os.remove("%s/experiment.js" %broken_experiment)
        self.assertFalse(validate(broken_experiment))
        shutil.copyfile("%s/pizza.js" %broken_experiment,"%s/experiment.js" %broken_experiment)

        # Invalid field for template
        broken_config = self.config[:]
        broken_config[0]["template"] = "invalid_framework"
        self.save_config(broken_config,broken_experiment)
        self.assertFalse(validate(broken_experiment))

        # Missing required field
        broken_config = self.config[:]
        del broken_config[0]["exp_id"]
        self.save_config(broken_config,broken_experiment)
        self.assertFalse(validate(broken_experiment))
Example #3
0
def install_experiments(experiment_tags=None, repo_type="experiments"):

    # We will return list of experiments that did not install successfully
    errored_experiments = []

    tmpdir = custom_battery_download(repos=[repo_type, "battery"])

    # The git commit is saved with the experiment as the "version"
    repo = Repo("%s/%s" % (tmpdir, repo_type))
    commit = repo.commit("master").__str__()

    experiments = get_experiments("%s/%s" % (tmpdir, repo_type), load=True, warning=False)
    if experiment_tags != None:
        experiments = [e for e in experiments if e[0]["exp_id"] in experiment_tags]

    for experiment in experiments:

        try:
            performance_variable = None
            rejection_variable = None
            if "experiment_variables" in experiment[0]:
                if isinstance(experiment[0]["experiment_variables"], list):
                    for var in experiment[0]["experiment_variables"]:
                        if var["type"].lower().strip() == "bonus":
                            performance_variable = parse_experiment_variable(var)
                        elif var["type"].lower().strip() == "credit":
                            rejection_variable = parse_experiment_variable(var)
                        else:
                            parse_experiment_variable(var)  # adds to database
            if isinstance(experiment[0]["reference"], list):
                reference = experiment[0]["reference"][0]
            else:
                reference = experiment[0]["reference"]
            cognitive_atlas_task = get_cognitiveatlas_task(experiment[0]["cognitive_atlas_task_id"])
            new_experiment, _ = ExperimentTemplate.objects.update_or_create(
                exp_id=experiment[0]["exp_id"],
                defaults={
                    "name": experiment[0]["name"],
                    "cognitive_atlas_task": cognitive_atlas_task,
                    "publish": bool(experiment[0]["publish"]),
                    "time": experiment[0]["time"],
                    "reference": reference,
                    "version": commit,
                    "template": experiment[0]["template"],
                    "performance_variable": performance_variable,
                    "rejection_variable": rejection_variable,
                },
            )
            new_experiment.save()
            experiment_folder = "%s/%s/%s" % (tmpdir, repo_type, experiment[0]["exp_id"])
            output_folder = "%s/%s/%s" % (media_dir, repo_type, experiment[0]["exp_id"])
            if os.path.exists(output_folder):
                shutil.rmtree(output_folder)
            copy_directory(experiment_folder, output_folder)
        except:
            errored_experiments.append(experiment[0]["exp_id"])

    shutil.rmtree(tmpdir)
    return errored_experiments
Example #4
0
def install_experiments(experiment_tags=None,repo_type="experiments"):

    # We will return list of experiments that did not install successfully
    errored_experiments = []

    tmpdir = custom_battery_download(repos=[repo_type,"battery"])

    # The git commit is saved with the experiment as the "version"
    repo = Repo("%s/%s" %(tmpdir,repo_type))
    commit = repo.commit('master').__str__()

    experiments = get_experiments("%s/%s" %(tmpdir,repo_type),load=True,warning=False)
    if experiment_tags != None:
        experiments = [e for e in experiments if e[0]["exp_id"] in experiment_tags]

    for experiment in experiments:

        try:
            performance_variable = None
            rejection_variable = None
            if "experiment_variables" in experiment[0]:
                if isinstance(experiment[0]["experiment_variables"],list):
                    for var in experiment[0]["experiment_variables"]:
                        if var["type"].lower().strip() == "bonus":
                            performance_variable = parse_experiment_variable(var)
                        elif var["type"].lower().strip() == "credit":
                            rejection_variable = parse_experiment_variable(var)
                        else:
                            parse_experiment_variable(var) # adds to database
            if isinstance(experiment[0]["reference"],list):
                reference = experiment[0]["reference"][0]
            else:
                reference = experiment[0]["reference"]
            cognitive_atlas_task = get_cognitiveatlas_task(experiment[0]["cognitive_atlas_task_id"])
            new_experiment,_ = ExperimentTemplate.objects.update_or_create(exp_id=experiment[0]["exp_id"],
                                                                         defaults={"name":experiment[0]["name"],
                                                                                   "cognitive_atlas_task":cognitive_atlas_task,
                                                                                   "publish":bool(experiment[0]["publish"]),
                                                                                   "time":experiment[0]["time"],
                                                                                   "reference":reference,
                                                                                   "version":commit,
                                                                                   "template":experiment[0]["template"],
                                                                                   "performance_variable":performance_variable,
                                                                                   "rejection_variable":rejection_variable})
            new_experiment.save()
            experiment_folder = "%s/%s/%s" %(tmpdir,repo_type,experiment[0]["exp_id"])
            output_folder = "%s/%s/%s" %(media_dir,repo_type,experiment[0]["exp_id"])
            if os.path.exists(output_folder):
                shutil.rmtree(output_folder)
            copy_directory(experiment_folder,output_folder)
        except:
            errored_experiments.append(experiment[0]["exp_id"])

    shutil.rmtree(tmpdir)
    return errored_experiments
Example #5
0
def generate_base(battery_dest,tasks=None,experiment_repo=None,survey_repo=None,game_repo=None,
                  add_experiments=True,add_surveys=True,add_games=True,battery_repo=None,warning=True):
    '''generate_base returns a folder with downloaded experiments, surveys, and battery, either specified by the user or a temporary directory, to be used by generate_local and generate (for psiturk)
    :param battery_dest: [required] is the output folder for your battery. This folder MUST NOT EXIST.
    :param battery_repo: location of psiturk-battery repo to use as a template. If not specified, will be downloaded to a temporary directory
    :param experiment_repo: location of a expfactory-experiments repo to check for valid experiments. If not specified, will be downloaded to a temporary directory
    :param survey_repo: location of a expfactory-surveys repo to check for valid surveys. If not specified, will be downloaded to a temporary directory
    :param tasks: a list of experiments and surveys, meaning the "exp_id" variable in the config.json, to include. This variable also conincides with the tasks folder name.
    :param warning: show warnings when validating experiments (default True)
    '''
    if experiment_repo == None or battery_repo == None or survey_repo == None or game_repo == None:
        tmpdir = custom_battery_download()
        if experiment_repo == None:
            experiment_repo = "%s/experiments" %(tmpdir)     
        if battery_repo == None:
            battery_repo = "%s/battery" %(tmpdir)     
        if survey_repo == None:
            survey_repo = "%s/surveys" %(tmpdir)     
        if game_repo == None:
            game_repo = "%s/games" %(tmpdir)     


    # Copy battery skeleton to destination
    copy_directory(battery_repo,battery_dest)
    valid_experiments = []
    valid_surveys = []
    valid_games = []
    if add_experiments == True:
        valid_experiments = get_experiments(experiment_repo,warning=warning)
    if add_surveys == True:
        valid_surveys = get_experiments(survey_repo,warning=warning,repo_type="surveys")
    if add_games == True:
        valid_games = get_experiments(game_repo,warning=warning,repo_type="games")

    # If the user wants to select a subset
    if tasks != None:
        valid_experiments = [x for x in valid_experiments if os.path.basename(x) in [os.path.basename(e) for e in tasks]]
        valid_surveys = [x for x in valid_surveys if os.path.basename(x) in [os.path.basename(e) for e in tasks]]
        valid_games = [x for x in valid_games if os.path.basename(x) in [os.path.basename(e) for e in tasks]]

    base = {"battery_repo":battery_repo,
           "experiment_repo":experiment_repo,
           "survey_repo":survey_repo,
           "game_repo":game_repo,
           "experiments":valid_experiments,
           "surveys":valid_surveys,
           "games":valid_games}        

    return base
Example #6
0
def move_experiments(valid_experiments,battery_dest,repo_type="experiments"):
    '''move_experiments
    Moves valid experiments into the experiments folder in battery repo
    :param valid_experiments: a list of full paths to valid experiments
    :param battery_dest: full path to battery destination folder
    :param repo_type: the kind of task to move (default is experiments)
    '''

    moved_experiments = []
    for valid_experiment in valid_experiments:
        try:
            experiment_folder = os.path.basename(valid_experiment)
            copy_directory(valid_experiment,"%s/static/%s/%s" %(battery_dest,repo_type,experiment_folder))
            moved_experiments.append(valid_experiment)
        except:
           print "Cannot move %s, will not be added." %(valid_experiment)
    return moved_experiments
Example #7
0
def move_experiments(valid_experiments, battery_dest, repo_type="experiments"):
    '''move_experiments
    Moves valid experiments into the experiments folder in battery repo
    :param valid_experiments: a list of full paths to valid experiments
    :param battery_dest: full path to battery destination folder
    :param repo_type: the kind of task to move (default is experiments)
    '''

    moved_experiments = []
    for valid_experiment in valid_experiments:
        try:
            experiment_folder = os.path.basename(valid_experiment)
            copy_directory(
                valid_experiment, "%s/static/%s/%s" %
                (battery_dest, repo_type, experiment_folder))
            moved_experiments.append(valid_experiment)
        except:
            print("Cannot move %s, will not be added." % (valid_experiment))
    return moved_experiments
Example #8
0
def install_experiment_static(experiment,
                              to_dir,
                              from_dir,
                              update=True,
                              version=None):
    '''install_experiment_static will install an experiment object static files to
    the battery static folder. In the case of a special expfactory template (survey, experiment,
    or game) the template is rendered and then saved. If successful, returns True, otherwise False.
    :param experiment: the expdj.apps.experiments.models.Experiment
    :param to_dir: the directory to install to, typically in a battery folder
    :param from_dir: the temporary directory
    :param update: if the experiment files exist, remove them and install again (an update)
    :param version: if specified, will write a version id to the folder in file VERSION
    '''
    if os.path.exists(to_dir):
        if update == True:
            shutil.rmtree(to_dir)
        else:
            # Experiment static install fail, found files and update is not True
            return False

    # Copy all experiment files into the folder
    copy_directory(from_dir, to_dir)
    battery = experiment.battery
    router_url = (
        "%s%s" %
        (DOMAIN_NAME, battery.get_router_url(experiment.id))).encode('utf-8')

    if experiment.template in ['survey', 'jspsych']:
        index_html = install_experiment_template(experiment=experiment,
                                                 battery=battery,
                                                 router_url=router_url,
                                                 to_dir=to_dir)

    else:
        try:
            index_html = install_experiment_custom(experiment=experiment,
                                                   battery=battery,
                                                   router_url=router_url,
                                                   to_dir=to_dir)
        except Exception, message:
            return message
Example #9
0
def tmp_experiment(folder=None, battery_folder=None):
    '''generate temporary directory with experiment
    :param folder: full path to experiment folder to preview (experiment, survey, or game). If none specified, PWD is used
    :param battery_folder: full path to battery folder to use as a template. If none specified, the expfactory-battery repo will be used.
    '''
    if folder == None:
        folder = os.path.abspath(os.getcwd())

    if battery_folder == None:
        tmpdir = custom_battery_download(repos=["battery"])
    # If user has supplied a local battery folder, copy to tempdir
    else:
        tmpdir = tempfile.mkdtemp()
        copy_directory(battery_folder, "%s/battery" % tmpdir)

    experiment = load_experiment("%s" % folder)
    tag = experiment[0]["exp_id"]

    # Determine experiment template
    experiment_type = "experiments"
    if experiment[0]["template"] == "survey":
        experiment_type = "surveys"
    elif experiment[0]["template"] == "phaser":
        experiment_type = "games"

    # We will copy the entire experiment into the battery folder
    battery_folder = "%s/battery" % (tmpdir)
    experiment_folder = "%s/static/%s/%s" % (battery_folder, experiment_type,
                                             tag)
    if os.path.exists(experiment_folder):
        shutil.rmtree(experiment_folder)
    copy_directory(folder, experiment_folder)
    index_file = "%s/index.html" % (battery_folder)

    # Generate code for js and css
    exp_template = get_experiment_html(experiment, experiment_folder)
    filey = open(index_file, "w")
    filey.writelines(exp_template)
    filey.close()
    os.chdir(battery_folder)
    return tmpdir
Example #10
0
def tmp_experiment(folder=None,battery_folder=None):
    '''generate temporary directory with experiment
    :param folder: full path to experiment folder to preview (experiment, survey, or game). If none specified, PWD is used
    :param battery_folder: full path to battery folder to use as a template. If none specified, the expfactory-battery repo will be used.
    '''
    if folder==None:
        folder=os.path.abspath(os.getcwd())

    if battery_folder == None:
        tmpdir = custom_battery_download(repos=["battery"])
    # If user has supplied a local battery folder, copy to tempdir
    else:
        tmpdir = tempfile.mkdtemp()
        copy_directory(battery_folder,"%s/battery" %tmpdir)
        
    experiment = load_experiment("%s" %folder)
    tag = experiment[0]["exp_id"]

    # Determine experiment template
    experiment_type = "experiments"
    if experiment[0]["template"] == "survey":
        experiment_type = "surveys"
    elif experiment[0]["template"] == "phaser":
        experiment_type = "games"

    # We will copy the entire experiment into the battery folder
    battery_folder = "%s/battery" %(tmpdir)
    experiment_folder = "%s/static/%s/%s" %(battery_folder,experiment_type,tag)
    if os.path.exists(experiment_folder):
        shutil.rmtree(experiment_folder)
    copy_directory(folder,experiment_folder)
    index_file = "%s/index.html" %(battery_folder)
        
    # Generate code for js and css
    exp_template = get_experiment_html(experiment,experiment_folder)
    filey = open(index_file,"w")
    filey.writelines(exp_template)
    filey.close()
    os.chdir(battery_folder)
    return tmpdir
Example #11
0
def main(args,parser,subparser):

    template = 'build/docker/Dockerfile.template'

    # Full path to template is required if provided via input
    if args.input is not None:
        template = args.input

    template = get_template(template)
    
    # For now, only one database provided
    database = args.database
    studyid = args.studyid
    experiments = args.experiments
    branch = "-b %s" %os.environ.get('EXPFACTORY_BRANCH','master')

    headless = "false"
    if args.headless is True:
        headless = "true"

    template = sub_template(template,"{{studyid}}",studyid)
    template = sub_template(template,"{{database}}",database)
    template = sub_template(template,"{{headless}}",headless)
    template = sub_template(template,"{{branch}}",branch)

    if args.headless is True:
        bot.info("Headless build detected, you will need to generate tokens for application entry with expfactory users --new")

    library = get_library(key='name')

    apps = "\n"

    # Add local experiments to library, first preference
    local_installs = 0
    for experiment in experiments:
        if os.path.exists(experiment):

            bot.info('local experiment %s found, validating...' %experiment)

            # Is the experiment valid?
            cli = ExperimentValidator()
            valid = cli.validate(experiment, cleanup=False)

            if valid is True:
                local_installs +=1
                config = load_experiment(experiment)
                exp_id = config['exp_id']

                # If we aren't building in the experiment directory, we need to copy there
                output_dir = "%s/%s" %(os.path.abspath(os.path.dirname(args.output)), exp_id)
                experiment_dir = os.path.abspath(experiment)
                if output_dir != experiment_dir:
                    copy_directory(experiment_dir, output_dir)

                config['local'] = os.path.abspath(experiment)
                library[exp_id] = config


    # Warn the user that local installs are not reproducible (from recipe)
    if local_installs > 0:
        bot.warning("%s local installs detected: build is not reproducible without experiment folders" %local_installs)

    # Build Image with Experiments
    for experiment in experiments:
        exp_id = os.path.basename(experiment)
        if exp_id in library:
            config = library[exp_id]

            app = "LABEL EXPERIMENT_%s /scif/apps/%s\n" %(exp_id, exp_id)

            # Here add custom build routine, should be list of lines
            if "install" in config:
                commands = "\n".join(["RUN %s "%s for x in config['install']]).strip('\n')
                app = "%s%s\n" %(app, commands)

            # The final installation step, either from Github (url) or local folder
            if "local" in config:
                app = "%sADD %s /scif/apps/%s\n" %(app, exp_id, exp_id)
                app = "%sWORKDIR /scif/apps\nRUN expfactory install %s\n" %(app, exp_id)
            else:
                app = "%sWORKDIR /scif/apps\nRUN expfactory install %s\n" %(app, config['github'])  
            apps = "%s%s\n" %(apps,app)


        else:
            bot.warning('%s not in library, check spelling & punctuation.' %exp_id)

    if apps == "\n":
        bot.error('No valid experiments found, cancelling recipe build.')
        sys.exit(1)

    template = sub_template(template,"{{experiments}}",apps)
    outfile = write_file(args.output,template)
    bot.log("Recipe written to %s" %outfile)
Example #12
0
from expfactory.experiment import get_experiments, get_validation_fields
from expfactory.utils import copy_directory, sub_template
from expfactory.vm import custom_battery_download
from glob import glob
import shutil
import json
import os

# Download experiments to temporary directory
tmpdir = custom_battery_download()

static_content = glob("%s/battery/static/*" %tmpdir)

# Update entire static directory
copy_to = os.path.abspath("static/")
for content in static_content:
    basename = os.path.basename(content)
    if os.path.isfile(content):
        shutil.copyfile(content,"%s/%s" %(copy_to,basename))
    else:
        if os.path.exists("%s/%s" %(copy_to,basename)):
            shutil.rmtree("%s/%s" %(copy_to,basename))
        copy_directory(content,"%s/%s" %(copy_to,basename))

shutil.rmtree(tmpdir)
Example #13
0
def generate_new_survey(battery, exp_id, questions, lookup=None, update=True):
    '''generate_new_survey will use the survey template to generate a new survey (with config.json) in
    the install_dir. If the folder already exists, the files will be replaced given that update=True (default)
    :param battery: the battery to install the experiment to.
    :param exp_id: the exp_id, the unique id for the survey
    :param questions: the file handle for the questions
    :param update: Replace or update the files, if the survey already exists (default is True)
    :param lookup: (not required) a dictionary of values to look up for the config.json
    '''
    # First install to temporary directory
    tmpdir = tempfile.mkdtemp()

    # What is the battery install_dir?
    install_dir = battery.get_install_dir()

    # Copy the survey template to the folder (all required files)
    needs_validation = "%s/%s" % (tmpdir, exp_id)
    copy_directory(survey_template, needs_validation)

    # Write the questions there
    with open('%s/survey.tsv' % (needs_validation), 'wb+') as destination:
        for chunk in questions.chunks():
            destination.write(chunk)

    # Names must have quotes
    if "contributors" in lookup:
        if len(lookup['contributors']) > 0:
            lookup['contributors'] = ",".join(
                ['"%s"' % (n) for n in lookup["contributors"].split(',')])

    # Remove weird /M carriage returns
    if "notes" in lookup:
        if len(lookup["notes"]) > 0:
            lookup['notes'] = ''.join(lookup['notes'].replace('\r\n', ''))

    # Read in the template files for config.json
    template = get_template("surveys/new_survey/config.json.template")
    lookup["exp_id"] = exp_id
    del lookup['questions']
    config = template.render(context=lookup)
    write_template(config.encode('utf-8'),
                   "%s/config.json" % (needs_validation))
    os.remove("%s/config.json.template" % (needs_validation))

    # Finally, validate the survey. If valid, add to database.
    valid = validate_surveys([exp_id],
                             tmpdir,
                             survey_file="survey.tsv",
                             delim="\t")

    if valid == True:

        install_folder = '%s/%s' % (install_dir, exp_id)

        # The version will be the datetime string
        version = datetime.now().strftime("%s")

        # Install the folder as a new experiment!
        new_experiment, _ = Experiment.objects.update_or_create(
            exp_id=exp_id,
            battery=battery,
            defaults={
                "name": lookup["name"],
                "time": lookup["time"],
                "reference": lookup["reference"],
                "version": version,
                "template": "survey"
            })
        new_experiment.save()

        success = install_experiment_static(experiment=new_experiment,
                                            to_dir=install_folder,
                                            from_dir=needs_validation,
                                            version=version,
                                            update=update)

        if success != True:
            # If success returns as not true, is a mesage to indicate error
            valid = "%s: %s" (exp_id, success)

    shutil.rmtree(tmpdir)
    return valid
Example #14
0
def generate_base(battery_dest,
                  tasks=None,
                  experiment_repo=None,
                  survey_repo=None,
                  game_repo=None,
                  battery_repo=None,
                  warning=True):
    '''generate_base returns a folder with downloaded experiments, surveys, and battery, either specified by the user or a temporary directory, to be used by generate_local and generate (for psiturk)
    :param battery_dest: [required] is the output folder for your battery. This folder MUST NOT EXIST.
    :param battery_repo: location of psiturk-battery repo to use as a template. If not specified, will be downloaded to a temporary directory
    :param experiment_repo: location of a expfactory-experiments repo to check for valid experiments. If not specified, will be downloaded to a temporary directory
    :param survey_repo: location of a expfactory-surveys repo to check for valid surveys. If not specified, will be downloaded to a temporary directory
    :param tasks: a list of experiments and surveys, meaning the "exp_id" variable in the config.json, to include. This variable also conincides with the tasks folder name.
    :param warning: show warnings when validating experiments (default True)
    '''
    repos = []
    tmpdir = None
    if battery_repo == None:
        tmpdir = custom_battery_download(repos=['battery'])
        battery_repo = "%s/battery" % (tmpdir)
    if experiment_repo == None and survey_repo == None and game_repo == None:
        tmpdir = custom_battery_download(tmpdir,
                                         ['experiments', 'surveys', 'games'])
        experiment_repo = "%s/experiments" % (tmpdir)
        survey_repo = "%s/surveys" % (tmpdir)
        game_repo = "%s/games" % (tmpdir)

    # Copy battery skeleton to destination
    copy_directory(battery_repo, battery_dest)
    valid_experiments = []
    valid_surveys = []
    valid_games = []
    if experiment_repo is not None:
        valid_experiments = get_experiments(experiment_repo, warning=warning)
    if survey_repo is not None:
        valid_surveys = get_experiments(survey_repo,
                                        warning=warning,
                                        repo_type="surveys")
    if game_repo is not None:
        valid_games = get_experiments(game_repo,
                                      warning=warning,
                                      repo_type="games")
    # If the user wants to select a subset
    if tasks != None:
        valid_experiments = [
            x for x in valid_experiments
            if os.path.basename(x) in [os.path.basename(e) for e in tasks]
        ]
        valid_surveys = [
            x for x in valid_surveys
            if os.path.basename(x) in [os.path.basename(e) for e in tasks]
        ]
        valid_games = [
            x for x in valid_games
            if os.path.basename(x) in [os.path.basename(e) for e in tasks]
        ]

    base = {
        "battery_repo": battery_repo,
        "experiment_repo": experiment_repo,
        "survey_repo": survey_repo,
        "game_repo": game_repo,
        "experiments": valid_experiments,
        "surveys": valid_surveys,
        "games": valid_games
    }

    return base
Example #15
0
def generate_experiment_web(output_dir,experiment_folder=None,survey_folder=None,games_folder=None,
                            make_table=True,make_index=True,make_experiments=True,make_data=True,
                            make_surveys=True,make_games=True):
    '''get_experiment_table
    Generate a table with links to preview all experiments
    :param experiment_folder: folder with experiments inside
    :param survey_folder: folder with surveys inside
    :param games_folder: folder with games inside
    :param output_dir: output folder for experiment and table html, and battery files 
    :param make_table: generate table.html 
    :param make_index: generate d3 visualization index  
    :param make_experiments: generate experiment preview files (linked from table and index) 
    :param make_data: generate json/tsv data to download 
    :param make_surveys: generate static files for surveys repos 
    :param make_games: generate static files for games repos 
    '''
    repos=["experiments","battery"]
    if make_surveys == True:
        repos.append("surveys")

    if make_games == True:
        repos.append("games")     

    tmpdir = custom_battery_download(repos=repos)

    if not os.path.exists(output_dir):
        os.mkdir(output_dir)

    if experiment_folder == None:
        experiment_folder = "%s/experiments" %tmpdir
    experiments = get_experiments(experiment_folder,load=True, warning=False)
    experiment_tags = [x[0]["exp_id"] for x in experiments]
    battery_repo = "%s/battery" %(tmpdir)
    if survey_folder == None:
        survey_folder = "%s/surveys" %tmpdir
    if games_folder == None:
        games_folder = "%s/games" %tmpdir

    # If the user wants surveys and/or games, add them on to tasks
    tasks = experiments
    if make_surveys == True:
        surveys = get_experiments(survey_folder,load=True,warning=False,repo_type="surveys")
        survey_tags = [x[0]["exp_id"] for x in surveys]
        tasks = experiments + surveys

    if make_games == True:
        games = get_experiments(games_folder,load=True,warning=False,repo_type="games")
        games_tags = [x[0]["exp_id"] for x in games]
        tasks = tasks + games

    # Fields to keep for the table
    fields = ['preview','exp_id','template',
              'contributors','time',
              'cognitive_atlas_task_id']

    valid = pandas.DataFrame(columns=fields)
   
    # Make a table of experiment information
    for experiment in tasks:
        for field in experiment[0].keys():
            if field in fields:
                values = experiment[0][field]
                # Join lists with a comma
                if field == "reference":
                    if values != '':
                        values = '<a href="%s" target="_blank">%s</a>' %(values,values)
                if isinstance(values,list):
                    values = ",".join(values)
                valid.loc[experiment[0]["exp_id"],field] = values

        # Add a preview link
        valid.loc[experiment[0]["exp_id"],"preview"] = '<a href="%s.html" target="_blank">DEMO</a>' %(experiment[0]["exp_id"])
        
    # If the user wants to create the index page
    if make_index == True:
        output_index = os.path.abspath("%s/index.html" %output_dir)

        # For each experiment, we will prepare an interactive node for the site
        nodes = []
        for experiment in tasks:
            nodes.append('{"cluster": 1, "radius": "10", "color": colors[%s], "exp_id": "%s" }' %(choice([0,1,2]),experiment[0]["exp_id"]))

        # Generate index page
        index_template = get_template("%s/templates/expfactory_index.html" %get_installdir())        
        index_template = index_template.replace("[SUB_NODES_SUB]",",".join(nodes))
        index_template = index_template.replace("[SUB_TOTAL_SUB]",str(len(nodes)))
        filey = open(output_index,"wb")
        filey.writelines(index_template)
        filey.close()


    # Update entire static directory
    old_dirs = ["templates","static"]
    for folder in old_dirs:
        copy_to = os.path.abspath("%s/%s" %(output_dir,folder))
        copy_from = "%s/battery/%s" %(tmpdir,folder)
        if os.path.exists(copy_to):
            shutil.rmtree(copy_to)
        copy_directory(copy_from,copy_to)

    # Copy the favicon to web base
    shutil.copyfile("%s/battery/static/favicon.ico" %tmpdir,"%s/favicon.ico" %output_dir)

    # Clear old experiments
    experiment_dir = os.path.abspath("%s/static/experiments/" %output_dir)
    if os.path.exists(experiment_dir):
        shutil.rmtree(experiment_dir)

    # Clear old surveys, copy updated valid surveys into survey directory
    if make_surveys == True:
        survey_dir = os.path.abspath("%s/static/surveys/" %output_dir)
        if os.path.exists(survey_dir):
            shutil.rmtree(survey_dir)
        valid_surveys = ["%s/%s" %(survey_folder,x[0]["exp_id"]) for x in surveys]
        move_experiments(valid_surveys,battery_dest=output_dir,repo_type="surveys")

    # Clear old surveys, copy updated valid surveys into survey directory
    if make_games == True:
        games_dir = os.path.abspath("%s/static/games/" %output_dir)
        if os.path.exists(games_dir):
            shutil.rmtree(games_dir)
        valid_games = ["%s/%s" %(games_folder,x[0]["exp_id"]) for x in games]
        move_experiments(valid_games,battery_dest=output_dir,repo_type="games")

    # Copy updated valid experiments into our experiment directory
    valid_experiments = ["%s/%s" %(experiment_folder,x[0]["exp_id"]) for x in experiments]
    move_experiments(valid_experiments,battery_dest=output_dir)

    # If the user wants to make a table
    if make_table == True:

        table_template = get_template("%s/templates/table.html" %get_installdir())
        output_table = os.path.abspath("%s/table.html" %output_dir)

        # First prepare rendered table
        table = '<table id="fresh-table" class="table">\n<thead>\n'
        for field in fields:
            table = '%s<th data-field="%s" data-sortable="true">%s</th>' %(table,field,field)
        table = '%s\n</thead>\n<tbody>\n' %(table)

        for row in valid.iterrows():
            table = "%s<tr>\n" %(table)
            for field in row[1]:
                table = "%s<td>%s</td>\n" %(table,field)
            table = "%s</tr>\n" %(table)

        table = "%s</tbody></table>\n" %(table)

        # Write the new table
        table_template = table_template.replace("[[SUB_TABLE_SUB]]",table)
        filey = open("%s/table.html" %output_dir,"wb")
        filey.writelines(table_template)
        filey.close()

    if make_experiments == True:
        experiments_template = get_template("%s/templates/experiments_categories.html" %get_installdir())
        output_exp = os.path.abspath("%s/experiments.html" %output_dir)

        if "CIRCLE_BRANCH" in os.environ.keys():
            experiment_page = table_template    
        else:
            experiment_page = get_cognitiveatlas_hierarchy(experiment_tags=experiment_tags,get_html=True)

        # Write the new table
        filey = open(output_exp,"wb")
        filey.writelines(experiment_page)
        filey.close()
        
        # For each experiment, we will generate a demo page
        for experiment in experiments:
            demo_page = os.path.abspath("%s/%s.html" %(output_dir,experiment[0]["exp_id"]))
            exp_template = get_experiment_html(experiment,"%s/%s" %(experiment_folder,experiment[0]["exp_id"]))
            filey = open(demo_page,"wb")
            filey.writelines(exp_template)
            filey.close()

    # if the user wants to make surveys
    if make_surveys == True:
        for experiment in surveys:
            demo_page = os.path.abspath("%s/%s.html" %(output_dir,experiment[0]["exp_id"]))
            exp_template = get_experiment_html(experiment,"%s/%s" %(survey_folder,experiment[0]["exp_id"]))
            filey = open(demo_page,"wb")
            filey.writelines(exp_template)
            filey.close()


    # if the user wants to make surveys
    if make_games == True:
        for experiment in games:
            demo_page = os.path.abspath("%s/%s.html" %(output_dir,experiment[0]["exp_id"]))
            exp_template = get_experiment_html(experiment,"%s/%s" %(games_folder,experiment[0]["exp_id"]))
            filey = open(demo_page,"wb")
            filey.writelines(exp_template)
            filey.close()

    # If the user wants to make data
    if make_data == True:
        data_folder = os.path.abspath("%s/data" %output_dir)
        if not os.path.exists(data_folder):
            os.mkdir(data_folder)
        save_pretty_json("%s/expfactory-experiments.json" %(data_folder),json.loads(valid.to_json(orient="records")))
        valid.to_csv("%s/expfactory-experiments.tsv" %(data_folder),sep="\t",index=None)
        valid.to_pickle("%s/expfactory-experiments.pkl" %(data_folder))
Example #16
0
def main(args, parser, subparser):

    # List of experiments is required
    template = get_template('build/docker/Dockerfile.template')

    # For now, only one database provided
    database = args.database
    studyid = args.studyid
    experiments = args.experiments

    template = sub_template(template, "{{studyid}}", studyid)
    template = sub_template(template, "{{database}}", database)

    library = get_library(key='name')

    apps = "\n"

    # Add local experiments to library, first preference
    local_installs = 0
    for experiment in experiments:
        if os.path.exists(experiment):

            bot.info('local experiment %s found, validating...' % experiment)

            # Is the experiment valid?
            cli = ExperimentValidator()
            valid = cli.validate(experiment, cleanup=False)

            if valid is True:
                local_installs += 1
                config = load_experiment(experiment)
                exp_id = config['exp_id']

                # If we aren't building in the experiment directory, we need to copy there
                output_dir = "%s/%s" % (os.path.abspath(
                    os.path.dirname(args.output)), exp_id)
                experiment_dir = os.path.abspath(experiment)
                if output_dir != experiment_dir:
                    copy_directory(experiment_dir, output_dir)

                config['local'] = os.path.abspath(experiment)
                library[exp_id] = config

    # Warn the user that local installs are not reproducible (from recipe)
    if local_installs > 0:
        bot.warning(
            "%s local installs detected: build is not reproducible without experiment folders"
            % local_installs)

    # Build Image with Experiments
    for experiment in experiments:
        exp_id = os.path.basename(experiment)
        if exp_id in library:
            config = library[exp_id]

            app = "LABEL EXPERIMENT_%s /scif/apps/%s\n" % (exp_id, exp_id)

            # Here add custom build routine, should be list of lines
            if "install" in config:
                commands = "\n".join(
                    ["RUN %s " % s for x in config['install']]).strip('\n')
                app = "%s%s\n" % (app, commands)

            # The final installation step, either from Github (url) or local folder
            if "local" in config:
                app = "%sADD %s /scif/apps/%s\n" % (app, exp_id, exp_id)
                app = "%sWORKDIR /scif/apps\nRUN expfactory install %s\n" % (
                    app, exp_id)
            else:
                app = "%sWORKDIR /scif/apps\nRUN expfactory install %s\n" % (
                    app, config['github'])
            apps = "%s%s\n" % (apps, app)

        else:
            bot.warning('%s not in library, check spelling & punctuation.' %
                        exp_id)

    if apps == "\n":
        bot.error('No valid experiments found, cancelling recipe build.')
        sys.exit(1)

    template = sub_template(template, "{{experiments}}", apps)
    outfile = write_file(args.output, template)
    bot.log("Recipe written to %s" % outfile)
Example #17
0
def main(args, parser, subparser):

    template = "build/docker/Dockerfile.template"

    # Full path to template is required if provided via input
    if args.input is not None:
        template = args.input

    template = get_template(template)

    # For now, only one database provided
    database = args.database
    studyid = args.studyid
    experiments = args.experiments
    branch = "-b %s" % os.environ.get("EXPFACTORY_BRANCH", "master")

    headless = "false"
    if args.headless is True:
        headless = "true"

    template = sub_template(template, "{{studyid}}", studyid)
    template = sub_template(template, "{{database}}", database)
    template = sub_template(template, "{{headless}}", headless)
    template = sub_template(template, "{{branch}}", branch)

    if args.headless is True:
        bot.info(
            "Headless build detected, you will need to generate tokens for application entry with expfactory users --new"
        )

    library = get_library(key="name")

    apps = "\n"

    # Add local experiments to library, first preference
    local_installs = 0
    for experiment in experiments:
        if os.path.exists(experiment):

            bot.info("local experiment %s found, validating..." % experiment)

            # Is the experiment valid?
            cli = ExperimentValidator()
            valid = cli.validate(experiment, cleanup=False)

            if valid is True:
                local_installs += 1
                config = load_experiment(experiment)
                exp_id = config["exp_id"]

                # If we aren't building in the experiment directory, we need to copy there
                output_dir = "%s/%s" % (
                    os.path.abspath(os.path.dirname(args.output)),
                    exp_id,
                )
                experiment_dir = os.path.abspath(experiment)
                if output_dir != experiment_dir:
                    copy_directory(experiment_dir, output_dir)

                config["local"] = os.path.abspath(experiment)
                library[exp_id] = config

    # Warn the user that local installs are not reproducible (from recipe)
    if local_installs > 0:
        bot.warning(
            "%s local installs detected: build is not reproducible without experiment folders"
            % local_installs
        )

    # Build Image with Experiments
    for experiment in experiments:
        exp_id = os.path.basename(experiment)
        if exp_id in library:
            config = library[exp_id]

            app = "LABEL EXPERIMENT_%s /scif/apps/%s\n" % (exp_id, exp_id)

            # Here add custom build routine, should be list of lines
            if "install" in config:
                commands = "\n".join(["RUN %s " % s for x in config["install"]]).strip(
                    "\n"
                )
                app = "%s%s\n" % (app, commands)

            # The final installation step, either from Github (url) or local folder
            if "local" in config:
                app = "%sADD %s /scif/apps/%s\n" % (app, exp_id, exp_id)
                app = "%sWORKDIR /scif/apps\nRUN expfactory install %s\n" % (
                    app,
                    exp_id,
                )
            else:
                app = "%sWORKDIR /scif/apps\nRUN expfactory install %s\n" % (
                    app,
                    config["github"],
                )
            apps = "%s%s\n" % (apps, app)

        else:
            bot.warning("%s not in library, check spelling & punctuation." % exp_id)

    if apps == "\n":
        bot.error("No valid experiments found, cancelling recipe build.")
        sys.exit(1)

    template = sub_template(template, "{{experiments}}", apps)
    outfile = write_file(args.output, template)
    bot.log("Recipe written to %s" % outfile)