@@ -33,6 +33,7 @@ sections up to the index to be used with the `get_section` Tera function | |||||
- Add a `load_data` Tera function to load local CSV/TOML/JSON files | - Add a `load_data` Tera function to load local CSV/TOML/JSON files | ||||
- Add `relative_path` to pages and sections in templates | - Add `relative_path` to pages and sections in templates | ||||
- Do not have a trailing slash for the RSS permalinks | - Do not have a trailing slash for the RSS permalinks | ||||
- `serve` will now try to find other ports than 1111 rather than panicking | |||||
## 0.4.2 (2018-09-03) | ## 0.4.2 (2018-09-03) | ||||
@@ -146,8 +146,11 @@ impl Site { | |||||
self.content_path.join("_index.md") | self.content_path.join("_index.md") | ||||
} | } | ||||
pub fn enable_live_reload(&mut self) { | |||||
self.live_reload = get_available_port(); | |||||
/// We avoid the port the server is going to use as it's not bound yet | |||||
/// when calling this function and we could end up having tried to bind | |||||
/// both http and websocket server to the same port | |||||
pub fn enable_live_reload(&mut self, port_to_avoid: u16) { | |||||
self.live_reload = get_available_port(port_to_avoid); | |||||
} | } | ||||
/// Get all the orphan (== without section) pages in the site | /// Get all the orphan (== without section) pages in the site | ||||
@@ -1,12 +1,12 @@ | |||||
use std::net::TcpListener; | use std::net::TcpListener; | ||||
pub fn get_available_port() -> Option<u16> { | |||||
pub fn get_available_port(avoid: u16) -> Option<u16> { | |||||
(1000..9000) | (1000..9000) | ||||
.find(|port| port_is_available(*port)) | |||||
.find(|port| *port != avoid && port_is_available(*port)) | |||||
} | } | ||||
fn port_is_available(port: u16) -> bool { | |||||
pub fn port_is_available(port: u16) -> bool { | |||||
match TcpListener::bind(("127.0.0.1", port)) { | match TcpListener::bind(("127.0.0.1", port)) { | ||||
Ok(_) => true, | Ok(_) => true, | ||||
Err(_) => false, | Err(_) => false, | ||||
@@ -108,7 +108,7 @@ fn rebuild_done_handling(broadcaster: &Sender, res: Result<()>, reload_path: &st | |||||
} | } | ||||
} | } | ||||
fn create_new_site(interface: &str, port: &str, output_dir: &str, base_url: &str, config_file: &str) -> Result<(Site, String)> { | |||||
fn create_new_site(interface: &str, port: u16, output_dir: &str, base_url: &str, config_file: &str) -> Result<(Site, String)> { | |||||
let mut site = Site::new(env::current_dir().unwrap(), config_file)?; | let mut site = Site::new(env::current_dir().unwrap(), config_file)?; | ||||
let base_address = format!("{}:{}", base_url, port); | let base_address = format!("{}:{}", base_url, port); | ||||
@@ -122,7 +122,7 @@ fn create_new_site(interface: &str, port: &str, output_dir: &str, base_url: &str | |||||
site.set_base_url(base_url); | site.set_base_url(base_url); | ||||
site.set_output_path(output_dir); | site.set_output_path(output_dir); | ||||
site.load()?; | site.load()?; | ||||
site.enable_live_reload(); | |||||
site.enable_live_reload(port); | |||||
console::notify_site_size(&site); | console::notify_site_size(&site); | ||||
console::warn_about_ignored_pages(&site); | console::warn_about_ignored_pages(&site); | ||||
site.build()?; | site.build()?; | ||||
@@ -147,7 +147,7 @@ fn handle_directory<'a, 'b>(dir: &'a fs::Directory, req: &'b HttpRequest) -> io: | |||||
fs::NamedFile::open(path)?.respond_to(req) | fs::NamedFile::open(path)?.respond_to(req) | ||||
} | } | ||||
pub fn serve(interface: &str, port: &str, output_dir: &str, base_url: &str, config_file: &str) -> Result<()> { | |||||
pub fn serve(interface: &str, port: u16, output_dir: &str, base_url: &str, config_file: &str) -> Result<()> { | |||||
let start = Instant::now(); | let start = Instant::now(); | ||||
let (mut site, address) = create_new_site(interface, port, output_dir, base_url, config_file)?; | let (mut site, address) = create_new_site(interface, port, output_dir, base_url, config_file)?; | ||||
console::report_elapsed_time(start); | console::report_elapsed_time(start); | ||||
@@ -20,6 +20,8 @@ extern crate rebuild; | |||||
use std::time::Instant; | use std::time::Instant; | ||||
use utils::net::{get_available_port, port_is_available}; | |||||
mod cmd; | mod cmd; | ||||
mod console; | mod console; | ||||
mod cli; | mod cli; | ||||
@@ -55,7 +57,28 @@ fn main() { | |||||
}, | }, | ||||
("serve", Some(matches)) => { | ("serve", Some(matches)) => { | ||||
let interface = matches.value_of("interface").unwrap_or("127.0.0.1"); | let interface = matches.value_of("interface").unwrap_or("127.0.0.1"); | ||||
let port = matches.value_of("port").unwrap_or("1111"); | |||||
let mut port: u16 = match matches.value_of("port").unwrap().parse() { | |||||
Ok(x) => x, | |||||
Err(_) => { | |||||
console::error("The request port needs to be an integer"); | |||||
::std::process::exit(1); | |||||
} | |||||
}; | |||||
// Default one | |||||
if port != 1111 && !port_is_available(port) { | |||||
console::error("The requested port is not available"); | |||||
::std::process::exit(1); | |||||
} | |||||
if !port_is_available(port) { | |||||
port = if let Some(p) = get_available_port(1111) { | |||||
p | |||||
} else { | |||||
console::error("No port available."); | |||||
::std::process::exit(1); | |||||
} | |||||
} | |||||
let output_dir = matches.value_of("output_dir").unwrap(); | let output_dir = matches.value_of("output_dir").unwrap(); | ||||
let base_url = matches.value_of("base_url").unwrap(); | let base_url = matches.value_of("base_url").unwrap(); | ||||
console::info("Building site..."); | console::info("Building site..."); | ||||