1 module easyd.unix;
2 
3 // (C) 2014-2018 by Matthias Rossmy
4 // This file is distributed under the "Fair Use License v2"
5 
6 public import std.file; //must be imported here as public instead of easyd/package.d, otherwise the resolving of some functions would be ambigious
7 
8 import std.path;
9 import std.format;
10 import std.conv;
11 import std.algorithm;
12 import std.process;
13 import std.stdio;
14 
15 import easyd.base;
16 import easyd..string;
17 import easyd.stream;
18 
19 unittest
20 {
21 	assert(parentDir("/home/test")=="/home");
22 	assert(pathEqual("/home/test/bla/../","/home/test"));
23 	assert("/home/test".slash=="/home/test/");
24 	assert("/home/test/".slash=="/home/test/");
25 	assert("/home/test".unslash=="/home/test");
26 	assert("/home/test/".unslash=="/home/test");
27 	assert(fullPath("~/test")=="/home/"~userName~"/test");
28 	assert("../test/my.file".fullPathFrom("/home/bla")=="/home/test/my.file");
29 	assert(pureName("/tmp/test.tar.gz",false)=="test.tar");
30 	assert(pureName("/tmp/test.tar.gz",true)=="test");
31 	
32 	auto stream = new StdoutStream("echo test");
33 	assert(stream.readLine=="test");
34 }
35 
36 string parentDir(string s)
37 {
38 	return s.fullPath.dirName;
39 }
40 
41 bool resetDir(string d)
42 {
43 	Try(rmdirRecurse(d));
44 	return Try(mkdirRecurse(d));
45 }
46 
47 bool isExecutable(string fn, bool acceptDirs=true)
48 {
49 	try
50 	{
51 		return (acceptDirs || !isDir(fn)) && (format("%o",getAttributes(fn)).getEnd(1).to!int & 1) > 0;
52 	}catch(Exception e){
53 		return false;
54 	}
55 }
56 
57 bool isDir(string s)
58 {
59 	bool result = false;
60 	try
61 	{
62 		result = std.file.isDir(s);
63 	}catch(Exception e){}
64 	return result;
65 }
66 
67 bool pathEqual(string p1,string p2)
68 {
69 	return p1.fullPath.unslash==p2.fullPath.unslash;
70 }
71 
72 string slash(string s)
73 {
74 	return s.endsWith(dirSeparator)? s : s ~ dirSeparator;
75 }
76 
77 string unslash(string s)
78 {
79 	return s.endsWith(dirSeparator)? s.cutEnd(1) : s;
80 }
81 
82 string fullPath(string s)
83 {
84 	return s.expandTilde.absolutePath.buildNormalizedPath;
85 }
86 
87 string fullPathFrom(string s, string refPath)
88 {
89 	string refdir;
90 	if(refPath.exists && !refPath.isDir)
91 	{
92 		refdir = refPath.dirName;
93 	}else{
94 		refdir = refPath;
95 	}
96 	return s.expandTilde.absolutePath(refdir).buildNormalizedPath;
97 }
98 
99 string pureName(string s, bool multiStrip=false)
100 {
101 	s = s.baseName;
102 	if(multiStrip)
103 	{
104 		while(s.contains('.')) s = s.stripExtension;
105 		return s;
106 	}else{
107 		return s.stripExtension;
108 	}
109 }
110 
111 string userName()
112 {
113 	return fullPath("~").baseName;
114 }
115 
116 struct ScopedChdir
117 {
118 	string prevDir;
119 	string newDir;
120 	bool isTemp;
121 
122 	this(string newdir, bool istemp=false)
123 	{
124 		prevDir = getcwd;
125 		newDir = newdir.absolutePath;
126 		isTemp = istemp;
127 		chdir(newDir);
128 	}
129 
130 	~this()
131 	{
132 		chdir(prevDir);
133 		if(isTemp) rmdirRecurse(newDir);
134 	}
135 }
136 
137 void symLink(string source,string dest,bool relative=true)
138 {
139 	source = source.absolutePath;
140 	if(relative) source = source.relativePath(dest.dirName.absolutePath);
141 	Try(remove(dest));
142 	symlink(source,dest);
143 }
144 
145 string resolveLink(string symlink)
146 {
147 	try
148 	{
149 		symlink = symlink.absolutePath;
150 		return readLink(symlink).absolutePath(symlink.dirName);
151 	}catch(Exception e){
152 		return "";
153 	}
154 }
155 
156 bool isLink(string symlink)
157 {
158 	return resolveLink(symlink)!="";
159 }
160 
161 class StdoutStream : FileReader
162 {
163 	this(string command)
164 	{
165 		auto pipes = pipeShell(command,Redirect.stdout | Redirect.stderrToStdout);
166 		file = pipes.stdout;
167 	}
168 }
169 
170 class TarStream : StdoutStream
171 {
172 	this(string path)
173 	{
174 		super("tar -c "~path);
175 	}
176 }
177 
178 class UntarStream : FileWriter
179 {
180 	this()
181 	{
182 		auto pipes = pipeShell("tar -x",Redirect.stdin);
183 		file = pipes.stdin;
184 	}
185 }
186 
187 bool shellExec(string command, bool w=true, bool dbg=false)
188 {
189 	try
190 	{
191 		if(!w) command = "("~command~" &)";
192 		if(dbg) writeln(getcwd,"> ",command);
193 		auto pid = spawnShell(command);
194 		if(w)
195 		{
196 			auto rc = wait(pid);
197 			if(rc!=0 && dbg) writeln("Return code = ",rc);
198 			return rc==0;
199 		}
200 		return true;
201 	}catch(Exception e){
202 		if(dbg) writeln(e);
203 		return false;
204 	}
205 }
206 
207 bool isWritable(string fn)
208 {
209 	return shellExec("test -w \""~fn~"\"");
210 }
211 
212 bool rootPermissions()
213 {
214 	return isWritable("/");
215 }
216