about summary refs log blame commit diff
path: root/src/fstate.cc
blob: 0502a8524fa54603b812058427b182f6704cb93c (plain) (tree)
1
2
3
4
5
6
7
8
                    
                     
                   

 
                         
 
                                  



             
                                        
 
                                                                   


 
                      
 
                                    


 
                                 
 
                               
                                                
                                                                       



             
                                                       
 

                                                   


                                             

                                                             
 

                                                             
 



                                
              


 
                                                        
 
                               
                 


                                           
                      
                                 



     




                                           
                   

                                                            
                              
    
                                                           

                                        
                                                                  


                                                            

                                                                  
                                            

                                                                      
                                     
 

 
                    
                                              
 

                           

                                                                 
 
                                   







                                                                     
                                
                                    
                               


                                 
                      
                


 
                                                 
 
                                    

                    
 








                                                                                   
 




                                                    
                                           
                               

     




                                          
                                           

                             
 


                               








                                                  




                                                            
                            


                               
                


 
                           
 






                                                      


 
                                                      
 
                          
                                                     

                                                     
                        


 
                                              
 
                                                

                              
                                                            
                                     

                                            


                                                
 
                                                         
 

 
                                                 
 





                                                                  
    
                            
                                                           


                                                                    




                                                           





                                                            
 
                                                                         
                        
                       
                                

                               
                        
 

 
                                      
 




                                         
 
#include "fstate.hh"
#include "globals.hh"
#include "store.hh"


string printTerm(ATerm t)
{
    char * s = ATwriteToString(t);
    return s;
}


Error badTerm(const format & f, ATerm t)
{
    return Error(format("%1%, in `%2%'") % f.str() % printTerm(t));
}


Hash hashTerm(ATerm t)
{
    return hashString(printTerm(t));
}


ATerm termFromId(const FSId & id)
{
    string path = expandId(id);
    ATerm t = ATreadFromNamedFile(path.c_str());
    if (!t) throw Error(format("cannot read aterm from `%1%'") % path);
    return t;
}


FSId writeTerm(ATerm t, const string & suffix, FSId id)
{
    /* By default, the id of a term is its hash. */
    if (id == FSId()) id = hashTerm(t);

    string path = canonPath(nixStore + "/" + 
        (string) id + suffix + ".nix");
    if (!ATwriteToNamedTextFile(t, path.c_str()))
        throw Error(format("cannot write aterm %1%") % path);

//     debug(format("written term %1% = %2%") % (string) id %
//         printTerm(t));

    Transaction txn(nixDB);
    registerPath(txn, path, id);
    txn.commit();

    return id;
}


static void parsePaths(ATermList paths, StringSet & out)
{
    while (!ATisEmpty(paths)) {
        char * s;
        ATerm t = ATgetFirst(paths);
        if (!ATmatch(t, "<str>", &s))
            throw badTerm("not a path", t);
        out.insert(s);
        paths = ATgetNext(paths);
    }
}


static void checkSlice(const Slice & slice)
{
    if (slice.elems.size() == 0)
        throw Error("empty slice");

    StringSet decl;
    for (SliceElems::const_iterator i = slice.elems.begin();
         i != slice.elems.end(); i++)
        decl.insert(i->first);
    
    for (StringSet::const_iterator i = slice.roots.begin();
         i != slice.roots.end(); i++)
        if (decl.find(*i) == decl.end())
            throw Error(format("undefined root path `%1%'") % *i);
    
    for (SliceElems::const_iterator i = slice.elems.begin();
         i != slice.elems.end(); i++)
        for (StringSet::const_iterator j = i->second.refs.begin();
             j != i->second.refs.end(); j++)
            if (decl.find(*j) == decl.end())
                throw Error(
		    format("undefined path `%1%' referenced by `%2%'")
		    % *j % i->first);
}


/* Parse a slice. */
static bool parseSlice(ATerm t, Slice & slice)
{
    ATermList roots, elems;
    
    if (!ATmatch(t, "Slice([<list>], [<list>])", &roots, &elems))
        return false;

    parsePaths(roots, slice.roots);

    while (!ATisEmpty(elems)) {
        char * s1, * s2;
        ATermList refs;
        ATerm t = ATgetFirst(elems);
        if (!ATmatch(t, "(<str>, <str>, [<list>])", &s1, &s2, &refs))
            throw badTerm("not a slice element", t);
        SliceElem elem;
        elem.id = parseHash(s2);
        parsePaths(refs, elem.refs);
        slice.elems[s1] = elem;
        elems = ATgetNext(elems);
    }

    checkSlice(slice);
    return true;
}


static bool parseDerive(ATerm t, Derive & derive)
{
    ATermList outs, ins, args, bnds;
    char * builder;
    char * platform;

    if (!ATmatch(t, "Derive([<list>], [<list>], <str>, <str>, [<list>], [<list>])",
            &outs, &ins, &platform, &builder, &args, &bnds))
    {
        /* !!! compatibility -> remove eventually */
        if (!ATmatch(t, "Derive([<list>], [<list>], <str>, <str>, [<list>])",
                &outs, &ins, &builder, &platform, &bnds))
            return false;
        args = ATempty;
    }

    while (!ATisEmpty(outs)) {
        char * s1, * s2;
        ATerm t = ATgetFirst(outs);
        if (!ATmatch(t, "(<str>, <str>)", &s1, &s2))
            throw badTerm("not a derive output", t);
        derive.outputs[s1] = parseHash(s2);
        outs = ATgetNext(outs);
    }

    while (!ATisEmpty(ins)) {
        char * s;
        ATerm t = ATgetFirst(ins);
        if (!ATmatch(t, "<str>", &s))
            throw badTerm("not an id", t);
        derive.inputs.insert(parseHash(s));
        ins = ATgetNext(ins);
    }

    derive.builder = builder;
    derive.platform = platform;
    
    while (!ATisEmpty(args)) {
        char * s;
        ATerm arg = ATgetFirst(args);
        if (!ATmatch(arg, "<str>", &s))
            throw badTerm("string expected", arg);
        derive.args.push_back(s);
        args = ATgetNext(args);
    }

    while (!ATisEmpty(bnds)) {
        char * s1, * s2;
        ATerm bnd = ATgetFirst(bnds);
        if (!ATmatch(bnd, "(<str>, <str>)", &s1, &s2))
            throw badTerm("tuple of strings expected", bnd);
        derive.env[s1] = s2;
        bnds = ATgetNext(bnds);
    }

    return true;
}


FState parseFState(ATerm t)
{
    FState fs;
    if (parseSlice(t, fs.slice))
        fs.type = FState::fsSlice;
    else if (parseDerive(t, fs.derive))
        fs.type = FState::fsDerive;
    else throw badTerm("not an fstate-expression", t);
    return fs;
}


static ATermList unparsePaths(const StringSet & paths)
{
    ATermList l = ATempty;
    for (StringSet::const_iterator i = paths.begin();
         i != paths.end(); i++)
        l = ATinsert(l, ATmake("<str>", i->c_str()));
    return ATreverse(l);
}


static ATerm unparseSlice(const Slice & slice)
{
    ATermList roots = unparsePaths(slice.roots);
    
    ATermList elems = ATempty;
    for (SliceElems::const_iterator i = slice.elems.begin();
         i != slice.elems.end(); i++)
        elems = ATinsert(elems,
            ATmake("(<str>, <str>, <term>)",
                i->first.c_str(),
                ((string) i->second.id).c_str(),
                unparsePaths(i->second.refs)));

    return ATmake("Slice(<term>, <term>)", roots, elems);
}


static ATerm unparseDerive(const Derive & derive)
{
    ATermList outs = ATempty;
    for (DeriveOutputs::const_iterator i = derive.outputs.begin();
         i != derive.outputs.end(); i++)
        outs = ATinsert(outs,
            ATmake("(<str>, <str>)", 
                i->first.c_str(), ((string) i->second).c_str()));
    
    ATermList ins = ATempty;
    for (FSIdSet::const_iterator i = derive.inputs.begin();
         i != derive.inputs.end(); i++)
        ins = ATinsert(ins, ATmake("<str>", ((string) *i).c_str()));

    ATermList args = ATempty;
    for (Strings::const_iterator i = derive.args.begin();
         i != derive.args.end(); i++)
        args = ATinsert(args, ATmake("<str>", i->c_str()));

    ATermList env = ATempty;
    for (StringPairs::const_iterator i = derive.env.begin();
         i != derive.env.end(); i++)
        env = ATinsert(env,
            ATmake("(<str>, <str>)", 
                i->first.c_str(), i->second.c_str()));

    return ATmake("Derive(<term>, <term>, <str>, <str>, <term>, <term>)",
        ATreverse(outs),
        ATreverse(ins),
        derive.platform.c_str(),
        derive.builder.c_str(),
        ATreverse(args),
        ATreverse(env));
}


ATerm unparseFState(const FState & fs)
{
    if (fs.type == FState::fsSlice)
        return unparseSlice(fs.slice);
    else if (fs.type == FState::fsDerive)
        return unparseDerive(fs.derive);
    else abort();
}