about summary refs log blame commit diff
path: root/third_party/nix/src/libexpr/names.cc
blob: f559c13a61151386dfca971b84d16a271d9d920d (plain) (tree)
1
2
3
4
5
6
7
8
9
                   
 
                 
                  
               
 
                                 
 



                                                                      


                                                         
                                                                      

                                 
     
   
 
                                   
                 
                                                                       
     


                                            
                                                     
 

                                                        

                                                
 

                 
 


                                                                    
                                            

                
                                                                        

                
 
           
 
                                                              


                                  
 
                       
                   
                            
                
                                          
                
                           
                 
                                       
                
                     
                 
          
                   
   
 

                                                         
 

                                            
                               
                
                               
               
     
   
 
           
 
                                                  

                                 
                
 
 
                   
#include "names.hh"

#include <memory>

#include "util.hh"

namespace nix {

DrvName::DrvName() { name = ""; }

/* Parse a derivation name.  The `name' part of a derivation name is
   everything up to but not including the first dash *not* followed by
   a letter.  The `version' part is the rest (excluding the separating
   dash).  E.g., `apache-httpd-2.0.48' is parsed to (`apache-httpd',
   '2.0.48'). */
DrvName::DrvName(const string& s) : hits(0) {
  name = fullName = s;
  for (unsigned int i = 0; i < s.size(); ++i) {
    /* !!! isalpha/isdigit are affected by the locale. */
    if (s[i] == '-' && i + 1 < s.size() && (isalpha(s[i + 1]) == 0)) {
      name = string(s, 0, i);
      version = string(s, i + 1);
      break;
    }
  }
}

bool DrvName::matches(DrvName& n) {
  if (name != "*") {
    if (!regex) {
      regex = std::make_unique<std::regex>(name, std::regex::extended);
    }
    if (!std::regex_match(n.name, *regex)) {
      return false;
    }
  }
  return !(!version.empty() && version != n.version);
}

string nextComponent(string::const_iterator& p,
                     const string::const_iterator end) {
  /* Skip any dots and dashes (component separators). */
  while (p != end && (*p == '.' || *p == '-')) {
    ++p;
  }

  if (p == end) {
    return "";
  }

  /* If the first character is a digit, consume the longest sequence
     of digits.  Otherwise, consume the longest sequence of
     non-digit, non-separator characters. */
  string s;
  if (isdigit(*p) != 0) {
    while (p != end && (isdigit(*p) != 0)) {
      s += *p++;
    }
  } else {
    while (p != end && ((isdigit(*p) == 0) && *p != '.' && *p != '-')) {
      s += *p++;
    }
  }

  return s;
}

static bool componentsLT(const string& c1, const string& c2) {
  int n1;
  int n2;
  bool c1Num = string2Int(c1, n1);
  bool c2Num = string2Int(c2, n2);

  if (c1Num && c2Num) {
    return n1 < n2;
  }
  if (c1.empty() && c2Num) {
    return true;
  } else if (c1 == "pre" && c2 != "pre") {
    return true;
  } else if (c2 == "pre") {
    return false;
    /* Assume that `2.3a' < `2.3.1'. */
  } else if (c2Num) {
    return true;
  } else if (c1Num) {
    return false;
  } else {
    return c1 < c2;
  }
}

int compareVersions(const string& v1, const string& v2) {
  string::const_iterator p1 = v1.begin();
  string::const_iterator p2 = v2.begin();

  while (p1 != v1.end() || p2 != v2.end()) {
    string c1 = nextComponent(p1, v1.end());
    string c2 = nextComponent(p2, v2.end());
    if (componentsLT(c1, c2)) {
      return -1;
    }
    if (componentsLT(c2, c1)) {
      return 1;
    }
  }

  return 0;
}

DrvNames drvNamesFromArgs(const Strings& opArgs) {
  DrvNames result;
  for (auto& i : opArgs) {
    result.push_back(DrvName(i));
  }
  return result;
}

}  // namespace nix