Node Node::select(const std::string& selector,const std::string& type) const { std::string xpat; if(type=="css") xpat = xpath(selector); else if(type=="xpath") xpat = selector; else STENCILA_THROW(Exception,"Unknown selector type <"+type+">"); try { return pimpl_->select_single_node(xpat.c_str()).node(); } catch (const pugi::xpath_exception& e){ STENCILA_THROW(Exception,e.what()); } }
Message::Message(const std::string& message, Type type): Json::Document(message) { int items = size(); if(items<1) STENCILA_THROW(Exception,"Malformed WAMP message.\n message: " + message); if(type != NONE) { char code = (*this)[MESSAGE_TYPE].as<int>(); if(code!=type) STENCILA_THROW(Exception,"Mismatched message code.\n expected: " + string(type) + "\n got: " + string(code)); } }
JsonReader(std::istream& stream, bool optional=true): optional_(optional){ try { boost::property_tree::read_json(stream,tree_); } catch(const std::exception& error){ STENCILA_THROW(Exception,std::string("Error parsing JSON.\n what: ")+error.what()); } catch(...){ STENCILA_THROW(Exception,std::string("Unknown error parsing JSON.")); } }
Component& Component::managed(bool yes){ if(not managed()){ if(not yes) STENCILA_THROW(Exception,"It is only possible to turn on component management; use `manage(true)`."); repo(true); } return *this; }
Component::Instance Component::get(const std::string& address,const std::string& version,const std::string& comparison){ Instance instance; auto iterator = instances_.find(address); if(iterator!=instances_.end()){ instance = iterator->second; } else { // Try to find a component on the filesystem... std::string path = locate(address); //...if not found clone it from Stencila hub if(path.length()==0) path = Component::clone(address); // Load the component into memory Component* component; Type type = Component::type(path); if(type==NoneType){ STENCILA_THROW(Exception,"Path does not appear to be a Stencila component.\n path: "+path); } else if(type==ComponentType){ component = new Component; } else if(type==StencilType){ Stencil* stencil = new Stencil; stencil->read(path); component = stencil; } else if(type==ThemeType){ Theme* theme = new Theme; theme->read(path); component = theme; } else { STENCILA_THROW(Exception,"Type of component at path is not currently handled by `Component::get`.\n path: "+path+"\n type: "+type_name(type)); } component->path(path); component->hold(type); instance = {type,component}; } if(version.length()>0){ if(comparison.length()==0 or comparison=="=="){ Component& component = instance.as<Component>(); component.provide(version); } else { STENCILA_THROW(Exception,"Version comparison operator not yet supported <"+comparison+">"); } } return instance; }
Component& Component::sync(void) { if(origin().length()){ auto r = repo(); r->download(); r->merge("origin/master","master"); r->upload(); } else STENCILA_THROW(Exception,"Component is not published so can not be synced."); return *this; }
/** * Get a level for a string label * * Currently, only string representations of integers are implemeted. * In the future, text labels will also be allowed. */ static Level<Derived> level(const std::string& label) { int label_int; try { label_int = unstring<int>(label); } catch(...) { STENCILA_THROW(Exception,"Error attempting to parse string <"+label+"> as an integer"); } return level(label_int); }
Nodes Node::filter(const std::string& selector,const std::string& type) const { std::string xpat; if(type=="css") xpat = xpath(selector); else if(type=="xpath") xpat = selector; else STENCILA_THROW(Exception,"Unknown selector type <"+type+">"); try { // Select nodes pugi::xpath_node_set selected = pimpl_->select_nodes(xpat.c_str()); // Construct Nodes from pugi::xpath_node_set Nodes nodes; for(pugi::xpath_node_set::const_iterator it = selected.begin(); it != selected.end(); ++it){ nodes.push_back(it->node()); } return nodes; } catch (const pugi::xpath_exception& e){ STENCILA_THROW(Exception,e.what()); } }
void data_(const boost::property_tree::ptree& tree, Data& data, const std::string& name, const std::false_type& is_structure, const std::false_type& is_array){ // Data is not a reflector, so attempt to convert it to `Data` type try { data = tree.get_value<Data>(); } catch(...){ auto value = tree.get_value<std::string>(); STENCILA_THROW(Exception,"Error converting value.\n name: "+name+"\n value: "+value); } }
std::string call(const std::string& command) { FILE* stream = popen(command.c_str(), "r"); if(stream==NULL) STENCILA_THROW(Exception,"System call failed\n command: "+command); std::string string; const int buffer_size = 1028; char buffer[buffer_size]; while(fgets(buffer, buffer_size, stream) != NULL) string.append(buffer); pclose(stream); return trim(string); }
JsonReader& data(Type& data, const std::string& name, Args... args){ auto child = tree_.get_child_optional(name); if(child){ data_(*child,data,name,IsStructure<Type>(),IsArray<Type>()); } else { if(not optional_){ STENCILA_THROW(Exception,"JSON does not include property.\n name: "+name); } } return *this; }
Document& Document::read(const std::string& filename){ pugi::xml_parse_result result = doc_()->load_file( filename.c_str(), // See above for options used here (pugi::parse_default | pugi::parse_ws_pcdata) ); if(not result){ STENCILA_THROW(Exception,result.description()); } return *this; }
std::string Component::type_name(const Component::Type& type){ switch(type){ case NoneType: return "None"; case ComponentType: return "Component"; case StencilType: return "Stencil"; case ThemeType: return "Theme"; case PythonContextType: return "PythonContext"; case RContextType: return "RContext"; default: STENCILA_THROW(Exception,"`Component::type_name` has not been configured for type.\n type "+string(type)); break; } }
Document& Document::load(const std::string& xml){ // The`pugi::parse_ws_pcdata` option prevents whitespace only text // nodes from being discarded. // See http://pugixml.googlecode.com/svn/trunk/docs/manual/loading.html#manual.loading.options pugi::xml_parse_result result = doc_()->load_string( xml.c_str(), (pugi::parse_default | pugi::parse_ws_pcdata) ); if(not result){ STENCILA_THROW(Exception,result.description()); } return *this; }
Component& Component::provide(const std::string& version) { // Check this is a valid version number std::vector<std::string> vs = versions(); if(std::count(vs.begin(),vs.end(),version)==0){ STENCILA_THROW(Exception,"Component does not have version.\n address: "+address()+"\n version: "+version); } // Create directory std::string version_path = path()+"/.at/"+version; boost::filesystem::create_directories(version_path); // Archive into it Repository* repo = this->repo(); if(repo){ repo->archive(version,version_path); } return *this; }
std::string Stencil::interact(const std::string& code){ if(context_){ // Switch to stencil's directory boost::filesystem::path cwd = boost::filesystem::current_path(); boost::filesystem::path path = boost::filesystem::path(Component::path(true)); boost::filesystem::current_path(path); // Create a new unique id static char chars[] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', '0','1','2','3','4','5','6','7','8','9' }; std::string id; for(int cha=0;cha<8;cha++) id += chars[int(std::rand()/double(RAND_MAX)*sizeof(chars))]; // Run code in context auto result = context_->interact(code,id); // Return to original working directory boost::filesystem::current_path(cwd); return result; } else { STENCILA_THROW(Exception,"No context attached to this stencil"); } }
Component& Component::version(const std::string& version,const std::string& message) { std::string new_version; std::string tag_message = message; std::string current_version = Component::version(); boost::regex pattern("^(\\d+)\\.(\\d+)\\.(\\d+)$"); auto regex_uint = [](const boost::smatch& matches,unsigned int index){ return boost::lexical_cast<unsigned int>(std::string(matches[index].first,matches[index].second)); }; // Extract the semantic parts of the current version unsigned int current_major = 0; unsigned int current_minor = 0; unsigned int current_patch = 0; boost::smatch matches; if(boost::regex_match(current_version,matches,pattern)){ current_major = regex_uint(matches,1); current_minor = regex_uint(matches,2); current_patch = regex_uint(matches,3); } if(version=="patch"){ // Increment the patch number new_version = str(boost::format("%d.%d.%d")%current_major%current_minor%(current_patch+1)); } else if(version=="minor"){ // Increment the minor version number new_version = str(boost::format("%d.%d.0")%current_major%(current_minor+1)); } else if(version=="major"){ // Increment the minor version number new_version = str(boost::format("%d.0.0")%(current_major+1)); } else { // Check that the supplied version is greater, or equal to the current // version unsigned int new_major,new_minor,new_patch; boost::smatch matches; if(boost::regex_match(version,matches,pattern)){ new_major = regex_uint(matches,1); if(new_major<current_major) throw Exception(str( boost::format("Major version supplied is less than current major version (%d): %d")%current_major%new_major )); new_minor = regex_uint(matches,2); if(new_major==current_major and new_minor<current_minor) throw Exception(str( boost::format("Minor version supplied is less than current minor version (%d): %d")%current_minor%new_minor )); new_patch = regex_uint(matches,3); if(new_major==current_major and new_minor==current_minor and new_patch<current_patch) throw Exception(str( boost::format("Path version supplied is less than current path version (%d): %d")%current_patch%new_patch )); } else { STENCILA_THROW(Exception,"Version supplied is not in correct format (e.g. 1.3.2): "+version); } new_version = version; } if(tag_message.length()==0) tag_message = "Versioned changed to " + new_version; std::string name = ""; std::string email = ""; // Get, or create, repository for the component and tag it. Repository* repo = this->repo(true); if(repo->head()=="<none>") STENCILA_THROW(Exception,"Component has not been commited. Please do a commit() before a version()."); repo->tag(new_version,tag_message,name,email); return *this; }
Component& Component::publish(const std::string& address) { STENCILA_THROW(Exception,"Publishing of components is not yet implemented."); return *this; }
void execute(const std::string& command) { auto status = system(command.c_str()); if(status != 0) STENCILA_THROW(Exception,"System call failed\n command: "+command+"\n status: "+string(status)); }
Hub& Hub::signin(void){ std::string token = Host::env_var("STENCILA_HUB_TOKEN"); if(token.length()==0) STENCILA_THROW(Exception,"Environment variable STENCILA_HUB_TOKEN is not defined"); return signin(token); }
Json::Document Message::kwargs(void) const { if (size()<=CALL_KWARGS) STENCILA_THROW(Exception, "No keyword arguments supplied"); return (*this)[CALL_KWARGS]; }
const Component::Class& Component::class_(Type type){ const Class& clas = classes_[type]; if(not clas.defined) STENCILA_THROW(Exception,"Class with type enum has not been defined.\n type: "+type_name(type)); return clas; }