]> git.lizzy.rs Git - rust.git/blob - src/libstd/env.rs
Rollup merge of #23570 - dotdash:issue23550, r=eddyb
[rust.git] / src / libstd / env.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Inspection and manipulation of the process's environment.
12 //!
13 //! This module contains methods to inspect various aspects such as
14 //! environment varibles, process arguments, the current directory, and various
15 //! other important directories.
16
17 #![stable(feature = "env", since = "1.0.0")]
18
19 use prelude::v1::*;
20
21 use iter::IntoIterator;
22 use error::Error;
23 use ffi::{OsString, AsOsStr};
24 use fmt;
25 use io;
26 use path::{AsPath, PathBuf};
27 use sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering};
28 use sync::{StaticMutex, MUTEX_INIT};
29 use sys::os as os_imp;
30
31 /// Returns the current working directory as a `Path`.
32 ///
33 /// # Errors
34 ///
35 /// Returns an `Err` if the current working directory value is invalid.
36 /// Possible cases:
37 ///
38 /// * Current directory does not exist.
39 /// * There are insufficient permissions to access the current directory.
40 /// * The internal buffer is not large enough to hold the path.
41 ///
42 /// # Examples
43 ///
44 /// ```
45 /// use std::env;
46 ///
47 /// // We assume that we are in a valid directory.
48 /// let p = env::current_dir().unwrap();
49 /// println!("The current directory is {}", p.display());
50 /// ```
51 #[stable(feature = "env", since = "1.0.0")]
52 pub fn current_dir() -> io::Result<PathBuf> {
53     os_imp::getcwd()
54 }
55
56 /// Changes the current working directory to the specified path, returning
57 /// whether the change was completed successfully or not.
58 ///
59 /// # Examples
60 ///
61 /// ```
62 /// use std::env;
63 /// use std::path::Path;
64 ///
65 /// let root = Path::new("/");
66 /// assert!(env::set_current_dir(&root).is_ok());
67 /// println!("Successfully changed working directory to {}!", root.display());
68 /// ```
69 #[stable(feature = "env", since = "1.0.0")]
70 pub fn set_current_dir<P: AsPath + ?Sized>(p: &P) -> io::Result<()> {
71     os_imp::chdir(p.as_path())
72 }
73
74 static ENV_LOCK: StaticMutex = MUTEX_INIT;
75
76 /// An iterator over a snapshot of the environment variables of this process.
77 ///
78 /// This iterator is created through `std::env::vars()` and yields `(String,
79 /// String)` pairs.
80 #[stable(feature = "env", since = "1.0.0")]
81 pub struct Vars { inner: VarsOs }
82
83 /// An iterator over a snapshot of the environment variables of this process.
84 ///
85 /// This iterator is created through `std::env::vars_os()` and yields
86 /// `(OsString, OsString)` pairs.
87 #[stable(feature = "env", since = "1.0.0")]
88 pub struct VarsOs { inner: os_imp::Env }
89
90 /// Returns an iterator of (variable, value) pairs of strings, for all the
91 /// environment variables of the current process.
92 ///
93 /// The returned iterator contains a snapshot of the process's environment
94 /// variables at the time of this invocation, modifications to environment
95 /// variables afterwards will not be reflected in the returned iterator.
96 ///
97 /// # Panics
98 ///
99 /// While iterating, the returned iterator will panic if any key or value in the
100 /// environment is not valid unicode. If this is not desired, consider using the
101 /// `env::vars_os` function.
102 ///
103 /// # Examples
104 ///
105 /// ```
106 /// use std::env;
107 ///
108 /// // We will iterate through the references to the element returned by
109 /// // env::vars();
110 /// for (key, value) in env::vars() {
111 ///     println!("{}: {}", key, value);
112 /// }
113 /// ```
114 #[stable(feature = "env", since = "1.0.0")]
115 pub fn vars() -> Vars {
116     Vars { inner: vars_os() }
117 }
118
119 /// Returns an iterator of (variable, value) pairs of OS strings, for all the
120 /// environment variables of the current process.
121 ///
122 /// The returned iterator contains a snapshot of the process's environment
123 /// variables at the time of this invocation, modifications to environment
124 /// variables afterwards will not be reflected in the returned iterator.
125 ///
126 /// # Examples
127 ///
128 /// ```
129 /// use std::env;
130 ///
131 /// // We will iterate through the references to the element returned by
132 /// // env::vars_os();
133 /// for (key, value) in env::vars_os() {
134 ///     println!("{:?}: {:?}", key, value);
135 /// }
136 /// ```
137 #[stable(feature = "env", since = "1.0.0")]
138 pub fn vars_os() -> VarsOs {
139     let _g = ENV_LOCK.lock();
140     VarsOs { inner: os_imp::env() }
141 }
142
143 #[stable(feature = "env", since = "1.0.0")]
144 impl Iterator for Vars {
145     type Item = (String, String);
146     fn next(&mut self) -> Option<(String, String)> {
147         self.inner.next().map(|(a, b)| {
148             (a.into_string().unwrap(), b.into_string().unwrap())
149         })
150     }
151     fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
152 }
153
154 #[stable(feature = "env", since = "1.0.0")]
155 impl Iterator for VarsOs {
156     type Item = (OsString, OsString);
157     fn next(&mut self) -> Option<(OsString, OsString)> { self.inner.next() }
158     fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
159 }
160
161 /// Fetches the environment variable `key` from the current process.
162 ///
163 /// The returned result is `Ok(s)` if the environment variable is present and is
164 /// valid unicode. If the environment variable is not present, or it is not
165 /// valid unicode, then `Err` will be returned.
166 ///
167 /// # Examples
168 ///
169 /// ```
170 /// use std::env;
171 ///
172 /// let key = "HOME";
173 /// match env::var(key) {
174 ///     Ok(val) => println!("{}: {:?}", key, val),
175 ///     Err(e) => println!("couldn't interpret {}: {}", key, e),
176 /// }
177 /// ```
178 #[stable(feature = "env", since = "1.0.0")]
179 pub fn var<K: ?Sized>(key: &K) -> Result<String, VarError> where K: AsOsStr {
180     match var_os(key) {
181         Some(s) => s.into_string().map_err(VarError::NotUnicode),
182         None => Err(VarError::NotPresent)
183     }
184 }
185
186 /// Fetches the environment variable `key` from the current process, returning
187 /// None if the variable isn't set.
188 ///
189 /// # Examples
190 ///
191 /// ```
192 /// use std::env;
193 ///
194 /// let key = "HOME";
195 /// match env::var_os(key) {
196 ///     Some(val) => println!("{}: {:?}", key, val),
197 ///     None => println!("{} is not defined in the environment.", key)
198 /// }
199 /// ```
200 #[stable(feature = "env", since = "1.0.0")]
201 pub fn var_os<K: ?Sized>(key: &K) -> Option<OsString> where K: AsOsStr {
202     let _g = ENV_LOCK.lock();
203     os_imp::getenv(key.as_os_str())
204 }
205
206 /// Possible errors from the `env::var` method.
207 #[derive(Debug, PartialEq, Eq, Clone)]
208 #[stable(feature = "env", since = "1.0.0")]
209 pub enum VarError {
210     /// The specified environment variable was not present in the current
211     /// process's environment.
212     #[stable(feature = "env", since = "1.0.0")]
213     NotPresent,
214
215     /// The specified environment variable was found, but it did not contain
216     /// valid unicode data. The found data is returned as a payload of this
217     /// variant.
218     #[stable(feature = "env", since = "1.0.0")]
219     NotUnicode(OsString),
220 }
221
222 #[stable(feature = "env", since = "1.0.0")]
223 impl fmt::Display for VarError {
224     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
225         match *self {
226             VarError::NotPresent => write!(f, "environment variable not found"),
227             VarError::NotUnicode(ref s) => {
228                 write!(f, "environment variable was not valid unicode: {:?}", s)
229             }
230         }
231     }
232 }
233
234 #[stable(feature = "env", since = "1.0.0")]
235 impl Error for VarError {
236     fn description(&self) -> &str {
237         match *self {
238             VarError::NotPresent => "environment variable not found",
239             VarError::NotUnicode(..) => "environment variable was not valid unicode",
240         }
241     }
242 }
243
244 /// Sets the environment variable `k` to the value `v` for the currently running
245 /// process.
246 ///
247 /// # Examples
248 ///
249 /// ```
250 /// use std::env;
251 ///
252 /// let key = "KEY";
253 /// env::set_var(key, "VALUE");
254 /// assert_eq!(env::var(key), Ok("VALUE".to_string()));
255 /// ```
256 #[stable(feature = "env", since = "1.0.0")]
257 pub fn set_var<K: ?Sized, V: ?Sized>(k: &K, v: &V)
258     where K: AsOsStr, V: AsOsStr
259 {
260     let _g = ENV_LOCK.lock();
261     os_imp::setenv(k.as_os_str(), v.as_os_str())
262 }
263
264 /// Remove a variable from the environment entirely.
265 #[stable(feature = "env", since = "1.0.0")]
266 pub fn remove_var<K: ?Sized>(k: &K) where K: AsOsStr {
267     let _g = ENV_LOCK.lock();
268     os_imp::unsetenv(k.as_os_str())
269 }
270
271 /// An iterator over `Path` instances for parsing an environment variable
272 /// according to platform-specific conventions.
273 ///
274 /// This structure is returned from `std::env::split_paths`.
275 #[stable(feature = "env", since = "1.0.0")]
276 pub struct SplitPaths<'a> { inner: os_imp::SplitPaths<'a> }
277
278 /// Parses input according to platform conventions for the `PATH`
279 /// environment variable.
280 ///
281 /// Returns an iterator over the paths contained in `unparsed`.
282 ///
283 /// # Examples
284 ///
285 /// ```
286 /// use std::env;
287 ///
288 /// let key = "PATH";
289 /// match env::var_os(key) {
290 ///     Some(paths) => {
291 ///         for path in env::split_paths(&paths) {
292 ///             println!("'{}'", path.display());
293 ///         }
294 ///     }
295 ///     None => println!("{} is not defined in the environment.", key)
296 /// }
297 /// ```
298 #[stable(feature = "env", since = "1.0.0")]
299 pub fn split_paths<T: AsOsStr + ?Sized>(unparsed: &T) -> SplitPaths {
300     SplitPaths { inner: os_imp::split_paths(unparsed.as_os_str()) }
301 }
302
303 #[stable(feature = "env", since = "1.0.0")]
304 impl<'a> Iterator for SplitPaths<'a> {
305     type Item = PathBuf;
306     fn next(&mut self) -> Option<PathBuf> { self.inner.next() }
307     fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
308 }
309
310 /// Error type returned from `std::env::join_paths` when paths fail to be
311 /// joined.
312 #[derive(Debug)]
313 #[stable(feature = "env", since = "1.0.0")]
314 pub struct JoinPathsError {
315     inner: os_imp::JoinPathsError
316 }
317
318 /// Joins a collection of `Path`s appropriately for the `PATH`
319 /// environment variable.
320 ///
321 /// Returns an `OsString` on success.
322 ///
323 /// Returns an `Err` (containing an error message) if one of the input
324 /// `Path`s contains an invalid character for constructing the `PATH`
325 /// variable (a double quote on Windows or a colon on Unix).
326 ///
327 /// # Examples
328 ///
329 /// ```
330 /// use std::env;
331 /// use std::path::PathBuf;
332 ///
333 /// if let Some(path) = env::var_os("PATH") {
334 ///     let mut paths = env::split_paths(&path).collect::<Vec<_>>();
335 ///     paths.push(PathBuf::new("/home/xyz/bin"));
336 ///     let new_path = env::join_paths(paths.iter()).unwrap();
337 ///     env::set_var("PATH", &new_path);
338 /// }
339 /// ```
340 #[stable(feature = "env", since = "1.0.0")]
341 pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
342     where I: IntoIterator<Item=T>, T: AsOsStr
343 {
344     os_imp::join_paths(paths.into_iter()).map_err(|e| {
345         JoinPathsError { inner: e }
346     })
347 }
348
349 #[stable(feature = "env", since = "1.0.0")]
350 impl fmt::Display for JoinPathsError {
351     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
352         self.inner.fmt(f)
353     }
354 }
355
356 #[stable(feature = "env", since = "1.0.0")]
357 impl Error for JoinPathsError {
358     fn description(&self) -> &str { self.inner.description() }
359 }
360
361 /// Optionally returns the path to the current user's home directory if known.
362 ///
363 /// # Unix
364 ///
365 /// Returns the value of the 'HOME' environment variable if it is set
366 /// and not equal to the empty string.
367 ///
368 /// # Windows
369 ///
370 /// Returns the value of the 'HOME' environment variable if it is
371 /// set and not equal to the empty string. Otherwise, returns the value of the
372 /// 'USERPROFILE' environment variable if it is set and not equal to the empty
373 /// string.
374 ///
375 /// # Examples
376 ///
377 /// ```
378 /// use std::env;
379 ///
380 /// match env::home_dir() {
381 ///     Some(ref p) => println!("{}", p.display()),
382 ///     None => println!("Impossible to get your home dir!")
383 /// }
384 /// ```
385 #[stable(feature = "env", since = "1.0.0")]
386 pub fn home_dir() -> Option<PathBuf> {
387     os_imp::home_dir()
388 }
389
390 /// Returns the path to a temporary directory.
391 ///
392 /// On Unix, returns the value of the 'TMPDIR' environment variable if it is
393 /// set, otherwise for non-Android it returns '/tmp'. If Android, since there
394 /// is no global temporary folder (it is usually allocated per-app), we return
395 /// '/data/local/tmp'.
396 ///
397 /// On Windows, returns the value of, in order, the 'TMP', 'TEMP',
398 /// 'USERPROFILE' environment variable  if any are set and not the empty
399 /// string. Otherwise, tmpdir returns the path to the Windows directory.
400 #[stable(feature = "env", since = "1.0.0")]
401 pub fn temp_dir() -> PathBuf {
402     os_imp::temp_dir()
403 }
404
405 /// Optionally returns the filesystem path to the current executable which is
406 /// running but with the executable name.
407 ///
408 /// The path returned is not necessarily a "real path" to the executable as
409 /// there may be intermediate symlinks.
410 ///
411 /// # Errors
412 ///
413 /// Acquiring the path to the current executable is a platform-specific operation
414 /// that can fail for a good number of reasons. Some errors can include, but not
415 /// be limited to filesystem operations failing or general syscall failures.
416 ///
417 /// # Examples
418 ///
419 /// ```
420 /// use std::env;
421 ///
422 /// match env::current_exe() {
423 ///     Ok(exe_path) => println!("Path of this executable is: {}",
424 ///                               exe_path.display()),
425 ///     Err(e) => println!("failed to get current exe path: {}", e),
426 /// };
427 /// ```
428 #[stable(feature = "env", since = "1.0.0")]
429 pub fn current_exe() -> io::Result<PathBuf> {
430     os_imp::current_exe()
431 }
432
433 static EXIT_STATUS: AtomicIsize = ATOMIC_ISIZE_INIT;
434
435 /// Sets the process exit code
436 ///
437 /// Sets the exit code returned by the process if all supervised tasks
438 /// terminate successfully (without panicking). If the current root task panics
439 /// and is supervised by the scheduler then any user-specified exit status is
440 /// ignored and the process exits with the default panic status.
441 ///
442 /// Note that this is not synchronized against modifications of other threads.
443 #[unstable(feature = "exit_status", reason = "managing the exit status may change")]
444 pub fn set_exit_status(code: i32) {
445     EXIT_STATUS.store(code as isize, Ordering::SeqCst)
446 }
447
448 /// Fetches the process's current exit code. This defaults to 0 and can change
449 /// by calling `set_exit_status`.
450 #[unstable(feature = "exit_status", reason = "managing the exit status may change")]
451 pub fn get_exit_status() -> i32 {
452     EXIT_STATUS.load(Ordering::SeqCst) as i32
453 }
454
455 /// An iterator over the arguments of a process, yielding a `String` value
456 /// for each argument.
457 ///
458 /// This structure is created through the `std::env::args` method.
459 #[stable(feature = "env", since = "1.0.0")]
460 pub struct Args { inner: ArgsOs }
461
462 /// An iterator over the arguments of a process, yielding an `OsString` value
463 /// for each argument.
464 ///
465 /// This structure is created through the `std::env::args_os` method.
466 #[stable(feature = "env", since = "1.0.0")]
467 pub struct ArgsOs { inner: os_imp::Args }
468
469 /// Returns the arguments which this program was started with (normally passed
470 /// via the command line).
471 ///
472 /// The first element is traditionally the path to the executable, but it can be
473 /// set to arbitrary text, and it may not even exist, so this property should
474 /// not be relied upon for security purposes.
475 ///
476 /// # Panics
477 ///
478 /// The returned iterator will panic during iteration if any argument to the
479 /// process is not valid unicode. If this is not desired it is recommended to
480 /// use the `args_os` function instead.
481 ///
482 /// # Examples
483 ///
484 /// ```
485 /// use std::env;
486 ///
487 /// // Prints each argument on a separate line
488 /// for argument in env::args() {
489 ///     println!("{}", argument);
490 /// }
491 /// ```
492 #[stable(feature = "env", since = "1.0.0")]
493 pub fn args() -> Args {
494     Args { inner: args_os() }
495 }
496
497 /// Returns the arguments which this program was started with (normally passed
498 /// via the command line).
499 ///
500 /// The first element is traditionally the path to the executable, but it can be
501 /// set to arbitrary text, and it may not even exist, so this property should
502 /// not be relied upon for security purposes.
503 ///
504 /// # Examples
505 ///
506 /// ```
507 /// use std::env;
508 ///
509 /// // Prints each argument on a separate line
510 /// for argument in env::args_os() {
511 ///     println!("{:?}", argument);
512 /// }
513 /// ```
514 #[stable(feature = "env", since = "1.0.0")]
515 pub fn args_os() -> ArgsOs {
516     ArgsOs { inner: os_imp::args() }
517 }
518
519 #[stable(feature = "env", since = "1.0.0")]
520 impl Iterator for Args {
521     type Item = String;
522     fn next(&mut self) -> Option<String> {
523         self.inner.next().map(|s| s.into_string().unwrap())
524     }
525     fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
526 }
527
528 #[stable(feature = "env", since = "1.0.0")]
529 impl ExactSizeIterator for Args {
530     fn len(&self) -> usize { self.inner.len() }
531 }
532
533 #[stable(feature = "env", since = "1.0.0")]
534 impl Iterator for ArgsOs {
535     type Item = OsString;
536     fn next(&mut self) -> Option<OsString> { self.inner.next() }
537     fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
538 }
539
540 #[stable(feature = "env", since = "1.0.0")]
541 impl ExactSizeIterator for ArgsOs {
542     fn len(&self) -> usize { self.inner.len() }
543 }
544
545 /// Returns the page size of the current architecture in bytes.
546 #[unstable(feature = "page_size", reason = "naming and/or location may change")]
547 pub fn page_size() -> usize {
548     os_imp::page_size()
549 }
550
551 /// Constants associated with the current target
552 #[stable(feature = "env", since = "1.0.0")]
553 pub mod consts {
554     /// A string describing the architecture of the CPU that this is currently
555     /// in use.
556     #[stable(feature = "env", since = "1.0.0")]
557     pub const ARCH: &'static str = super::arch::ARCH;
558
559     #[stable(feature = "env", since = "1.0.0")]
560     pub const FAMILY: &'static str = super::os::FAMILY;
561
562     /// A string describing the specific operating system in use: in this
563     /// case, `linux`.
564     #[stable(feature = "env", since = "1.0.0")]
565     pub const OS: &'static str = super::os::OS;
566
567     /// Specifies the filename prefix used for shared libraries on this
568     /// platform: in this case, `lib`.
569     #[stable(feature = "env", since = "1.0.0")]
570     pub const DLL_PREFIX: &'static str = super::os::DLL_PREFIX;
571
572     /// Specifies the filename suffix used for shared libraries on this
573     /// platform: in this case, `.so`.
574     #[stable(feature = "env", since = "1.0.0")]
575     pub const DLL_SUFFIX: &'static str = super::os::DLL_SUFFIX;
576
577     /// Specifies the file extension used for shared libraries on this
578     /// platform that goes after the dot: in this case, `so`.
579     #[stable(feature = "env", since = "1.0.0")]
580     pub const DLL_EXTENSION: &'static str = super::os::DLL_EXTENSION;
581
582     /// Specifies the filename suffix used for executable binaries on this
583     /// platform: in this case, the empty string.
584     #[stable(feature = "env", since = "1.0.0")]
585     pub const EXE_SUFFIX: &'static str = super::os::EXE_SUFFIX;
586
587     /// Specifies the file extension, if any, used for executable binaries
588     /// on this platform: in this case, the empty string.
589     #[stable(feature = "env", since = "1.0.0")]
590     pub const EXE_EXTENSION: &'static str = super::os::EXE_EXTENSION;
591
592 }
593
594 #[cfg(target_os = "linux")]
595 mod os {
596     pub const FAMILY: &'static str = "unix";
597     pub const OS: &'static str = "linux";
598     pub const DLL_PREFIX: &'static str = "lib";
599     pub const DLL_SUFFIX: &'static str = ".so";
600     pub const DLL_EXTENSION: &'static str = "so";
601     pub const EXE_SUFFIX: &'static str = "";
602     pub const EXE_EXTENSION: &'static str = "";
603 }
604
605 #[cfg(target_os = "macos")]
606 mod os {
607     pub const FAMILY: &'static str = "unix";
608     pub const OS: &'static str = "macos";
609     pub const DLL_PREFIX: &'static str = "lib";
610     pub const DLL_SUFFIX: &'static str = ".dylib";
611     pub const DLL_EXTENSION: &'static str = "dylib";
612     pub const EXE_SUFFIX: &'static str = "";
613     pub const EXE_EXTENSION: &'static str = "";
614 }
615
616 #[cfg(target_os = "ios")]
617 mod os {
618     pub const FAMILY: &'static str = "unix";
619     pub const OS: &'static str = "ios";
620     pub const DLL_PREFIX: &'static str = "lib";
621     pub const DLL_SUFFIX: &'static str = ".dylib";
622     pub const DLL_EXTENSION: &'static str = "dylib";
623     pub const EXE_SUFFIX: &'static str = "";
624     pub const EXE_EXTENSION: &'static str = "";
625 }
626
627 #[cfg(target_os = "freebsd")]
628 mod os {
629     pub const FAMILY: &'static str = "unix";
630     pub const OS: &'static str = "freebsd";
631     pub const DLL_PREFIX: &'static str = "lib";
632     pub const DLL_SUFFIX: &'static str = ".so";
633     pub const DLL_EXTENSION: &'static str = "so";
634     pub const EXE_SUFFIX: &'static str = "";
635     pub const EXE_EXTENSION: &'static str = "";
636 }
637
638 #[cfg(target_os = "dragonfly")]
639 mod os {
640     pub const FAMILY: &'static str = "unix";
641     pub const OS: &'static str = "dragonfly";
642     pub const DLL_PREFIX: &'static str = "lib";
643     pub const DLL_SUFFIX: &'static str = ".so";
644     pub const DLL_EXTENSION: &'static str = "so";
645     pub const EXE_SUFFIX: &'static str = "";
646     pub const EXE_EXTENSION: &'static str = "";
647 }
648
649 #[cfg(target_os = "bitrig")]
650 mod os {
651     pub const FAMILY: &'static str = "unix";
652     pub const OS: &'static str = "bitrig";
653     pub const DLL_PREFIX: &'static str = "lib";
654     pub const DLL_SUFFIX: &'static str = ".so";
655     pub const DLL_EXTENSION: &'static str = "so";
656     pub const EXE_SUFFIX: &'static str = "";
657     pub const EXE_EXTENSION: &'static str = "";
658 }
659
660 #[cfg(target_os = "openbsd")]
661 mod os {
662     pub const FAMILY: &'static str = "unix";
663     pub const OS: &'static str = "openbsd";
664     pub const DLL_PREFIX: &'static str = "lib";
665     pub const DLL_SUFFIX: &'static str = ".so";
666     pub const DLL_EXTENSION: &'static str = "so";
667     pub const EXE_SUFFIX: &'static str = "";
668     pub const EXE_EXTENSION: &'static str = "";
669 }
670
671 #[cfg(target_os = "android")]
672 mod os {
673     pub const FAMILY: &'static str = "unix";
674     pub const OS: &'static str = "android";
675     pub const DLL_PREFIX: &'static str = "lib";
676     pub const DLL_SUFFIX: &'static str = ".so";
677     pub const DLL_EXTENSION: &'static str = "so";
678     pub const EXE_SUFFIX: &'static str = "";
679     pub const EXE_EXTENSION: &'static str = "";
680 }
681
682 #[cfg(target_os = "windows")]
683 mod os {
684     pub const FAMILY: &'static str = "windows";
685     pub const OS: &'static str = "windows";
686     pub const DLL_PREFIX: &'static str = "";
687     pub const DLL_SUFFIX: &'static str = ".dll";
688     pub const DLL_EXTENSION: &'static str = "dll";
689     pub const EXE_SUFFIX: &'static str = ".exe";
690     pub const EXE_EXTENSION: &'static str = "exe";
691 }
692
693 #[cfg(target_arch = "x86")]
694 mod arch {
695     pub const ARCH: &'static str = "x86";
696 }
697
698 #[cfg(target_arch = "x86_64")]
699 mod arch {
700     pub const ARCH: &'static str = "x86_64";
701 }
702
703 #[cfg(target_arch = "arm")]
704 mod arch {
705     pub const ARCH: &'static str = "arm";
706 }
707
708 #[cfg(target_arch = "aarch64")]
709 mod arch {
710     pub const ARCH: &'static str = "aarch64";
711 }
712
713 #[cfg(target_arch = "mips")]
714 mod arch {
715     pub const ARCH: &'static str = "mips";
716 }
717
718 #[cfg(target_arch = "mipsel")]
719 mod arch {
720     pub const ARCH: &'static str = "mipsel";
721 }
722
723 #[cfg(target_arch = "powerpc")]
724 mod arch {
725     pub const ARCH: &'static str = "powerpc";
726 }
727
728 #[cfg(test)]
729 mod tests {
730     use prelude::v1::*;
731     use super::*;
732
733     use iter::repeat;
734     use rand::{self, Rng};
735     use ffi::{OsString, OsStr};
736     use path::{Path, PathBuf};
737
738     fn make_rand_name() -> OsString {
739         let mut rng = rand::thread_rng();
740         let n = format!("TEST{}", rng.gen_ascii_chars().take(10)
741                                      .collect::<String>());
742         let n = OsString::from_string(n);
743         assert!(var_os(&n).is_none());
744         n
745     }
746
747     fn eq(a: Option<OsString>, b: Option<&str>) {
748         assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::from_str).map(|s| &*s));
749     }
750
751     #[test]
752     fn test_set_var() {
753         let n = make_rand_name();
754         set_var(&n, "VALUE");
755         eq(var_os(&n), Some("VALUE"));
756     }
757
758     #[test]
759     fn test_remove_var() {
760         let n = make_rand_name();
761         set_var(&n, "VALUE");
762         remove_var(&n);
763         eq(var_os(&n), None);
764     }
765
766     #[test]
767     fn test_set_var_overwrite() {
768         let n = make_rand_name();
769         set_var(&n, "1");
770         set_var(&n, "2");
771         eq(var_os(&n), Some("2"));
772         set_var(&n, "");
773         eq(var_os(&n), Some(""));
774     }
775
776     #[test]
777     fn test_var_big() {
778         let mut s = "".to_string();
779         let mut i = 0;
780         while i < 100 {
781             s.push_str("aaaaaaaaaa");
782             i += 1;
783         }
784         let n = make_rand_name();
785         set_var(&n, &s);
786         eq(var_os(&n), Some(&s));
787     }
788
789     #[test]
790     fn test_self_exe_path() {
791         let path = current_exe();
792         assert!(path.is_ok());
793         let path = path.unwrap();
794
795         // Hard to test this function
796         assert!(path.is_absolute());
797     }
798
799     #[test]
800     fn test_env_set_get_huge() {
801         let n = make_rand_name();
802         let s = repeat("x").take(10000).collect::<String>();
803         set_var(&n, &s);
804         eq(var_os(&n), Some(&s));
805         remove_var(&n);
806         eq(var_os(&n), None);
807     }
808
809     #[test]
810     fn test_env_set_var() {
811         let n = make_rand_name();
812
813         let mut e = vars_os();
814         set_var(&n, "VALUE");
815         assert!(!e.any(|(k, v)| {
816             &*k == &*n && &*v == "VALUE"
817         }));
818
819         assert!(vars_os().any(|(k, v)| {
820             &*k == &*n && &*v == "VALUE"
821         }));
822     }
823
824     #[test]
825     fn test() {
826         assert!((!Path::new("test-path").is_absolute()));
827
828         current_dir().unwrap();
829     }
830
831     #[test]
832     #[cfg(windows)]
833     fn split_paths_windows() {
834         fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
835             split_paths(unparsed).collect::<Vec<_>>() ==
836                 parsed.iter().map(|s| PathBuf::new(*s)).collect::<Vec<_>>()
837         }
838
839         assert!(check_parse("", &mut [""]));
840         assert!(check_parse(r#""""#, &mut [""]));
841         assert!(check_parse(";;", &mut ["", "", ""]));
842         assert!(check_parse(r"c:\", &mut [r"c:\"]));
843         assert!(check_parse(r"c:\;", &mut [r"c:\", ""]));
844         assert!(check_parse(r"c:\;c:\Program Files\",
845                             &mut [r"c:\", r"c:\Program Files\"]));
846         assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"]));
847         assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#,
848                             &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"]));
849     }
850
851     #[test]
852     #[cfg(unix)]
853     fn split_paths_unix() {
854         fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
855             split_paths(unparsed).collect::<Vec<_>>() ==
856                 parsed.iter().map(|s| PathBuf::new(*s)).collect::<Vec<_>>()
857         }
858
859         assert!(check_parse("", &mut [""]));
860         assert!(check_parse("::", &mut ["", "", ""]));
861         assert!(check_parse("/", &mut ["/"]));
862         assert!(check_parse("/:", &mut ["/", ""]));
863         assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"]));
864     }
865
866     #[test]
867     #[cfg(unix)]
868     fn join_paths_unix() {
869         fn test_eq(input: &[&str], output: &str) -> bool {
870             &*join_paths(input.iter().cloned()).unwrap() ==
871                 OsStr::from_str(output)
872         }
873
874         assert!(test_eq(&[], ""));
875         assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"],
876                          "/bin:/usr/bin:/usr/local/bin"));
877         assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""],
878                          ":/bin:::/usr/bin:"));
879         assert!(join_paths(["/te:st"].iter().cloned()).is_err());
880     }
881
882     #[test]
883     #[cfg(windows)]
884     fn join_paths_windows() {
885         fn test_eq(input: &[&str], output: &str) -> bool {
886             &*join_paths(input.iter().cloned()).unwrap() ==
887                 OsStr::from_str(output)
888         }
889
890         assert!(test_eq(&[], ""));
891         assert!(test_eq(&[r"c:\windows", r"c:\"],
892                         r"c:\windows;c:\"));
893         assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""],
894                         r";c:\windows;;;c:\;"));
895         assert!(test_eq(&[r"c:\te;st", r"c:\"],
896                         r#""c:\te;st";c:\"#));
897         assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err());
898     }
899     }