1// Copyright 2016 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package os_test
6
7import (
8	"bytes"
9	"errors"
10	"fmt"
11	"io/fs"
12	"log"
13	"os"
14	"path/filepath"
15	"sync"
16	"time"
17)
18
19func ExampleOpenFile() {
20	f, err := os.OpenFile("notes.txt", os.O_RDWR|os.O_CREATE, 0644)
21	if err != nil {
22		log.Fatal(err)
23	}
24	if err := f.Close(); err != nil {
25		log.Fatal(err)
26	}
27}
28
29func ExampleOpenFile_append() {
30	// If the file doesn't exist, create it, or append to the file
31	f, err := os.OpenFile("access.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
32	if err != nil {
33		log.Fatal(err)
34	}
35	if _, err := f.Write([]byte("appended some data\n")); err != nil {
36		f.Close() // ignore error; Write error takes precedence
37		log.Fatal(err)
38	}
39	if err := f.Close(); err != nil {
40		log.Fatal(err)
41	}
42}
43
44func ExampleChmod() {
45	if err := os.Chmod("some-filename", 0644); err != nil {
46		log.Fatal(err)
47	}
48}
49
50func ExampleChtimes() {
51	mtime := time.Date(2006, time.February, 1, 3, 4, 5, 0, time.UTC)
52	atime := time.Date(2007, time.March, 2, 4, 5, 6, 0, time.UTC)
53	if err := os.Chtimes("some-filename", atime, mtime); err != nil {
54		log.Fatal(err)
55	}
56}
57
58func ExampleFileMode() {
59	fi, err := os.Lstat("some-filename")
60	if err != nil {
61		log.Fatal(err)
62	}
63
64	fmt.Printf("permissions: %#o\n", fi.Mode().Perm()) // 0o400, 0o777, etc.
65	switch mode := fi.Mode(); {
66	case mode.IsRegular():
67		fmt.Println("regular file")
68	case mode.IsDir():
69		fmt.Println("directory")
70	case mode&fs.ModeSymlink != 0:
71		fmt.Println("symbolic link")
72	case mode&fs.ModeNamedPipe != 0:
73		fmt.Println("named pipe")
74	}
75}
76
77func ExampleErrNotExist() {
78	filename := "a-nonexistent-file"
79	if _, err := os.Stat(filename); errors.Is(err, fs.ErrNotExist) {
80		fmt.Println("file does not exist")
81	}
82	// Output:
83	// file does not exist
84}
85
86func ExampleExpand() {
87	mapper := func(placeholderName string) string {
88		switch placeholderName {
89		case "DAY_PART":
90			return "morning"
91		case "NAME":
92			return "Gopher"
93		}
94
95		return ""
96	}
97
98	fmt.Println(os.Expand("Good ${DAY_PART}, $NAME!", mapper))
99
100	// Output:
101	// Good morning, Gopher!
102}
103
104func ExampleExpandEnv() {
105	os.Setenv("NAME", "gopher")
106	os.Setenv("BURROW", "/usr/gopher")
107
108	fmt.Println(os.ExpandEnv("$NAME lives in ${BURROW}."))
109
110	// Output:
111	// gopher lives in /usr/gopher.
112}
113
114func ExampleLookupEnv() {
115	show := func(key string) {
116		val, ok := os.LookupEnv(key)
117		if !ok {
118			fmt.Printf("%s not set\n", key)
119		} else {
120			fmt.Printf("%s=%s\n", key, val)
121		}
122	}
123
124	os.Setenv("SOME_KEY", "value")
125	os.Setenv("EMPTY_KEY", "")
126
127	show("SOME_KEY")
128	show("EMPTY_KEY")
129	show("MISSING_KEY")
130
131	// Output:
132	// SOME_KEY=value
133	// EMPTY_KEY=
134	// MISSING_KEY not set
135}
136
137func ExampleGetenv() {
138	os.Setenv("NAME", "gopher")
139	os.Setenv("BURROW", "/usr/gopher")
140
141	fmt.Printf("%s lives in %s.\n", os.Getenv("NAME"), os.Getenv("BURROW"))
142
143	// Output:
144	// gopher lives in /usr/gopher.
145}
146
147func ExampleUnsetenv() {
148	os.Setenv("TMPDIR", "/my/tmp")
149	defer os.Unsetenv("TMPDIR")
150}
151
152func ExampleReadDir() {
153	files, err := os.ReadDir(".")
154	if err != nil {
155		log.Fatal(err)
156	}
157
158	for _, file := range files {
159		fmt.Println(file.Name())
160	}
161}
162
163func ExampleMkdirTemp() {
164	dir, err := os.MkdirTemp("", "example")
165	if err != nil {
166		log.Fatal(err)
167	}
168	defer os.RemoveAll(dir) // clean up
169
170	file := filepath.Join(dir, "tmpfile")
171	if err := os.WriteFile(file, []byte("content"), 0666); err != nil {
172		log.Fatal(err)
173	}
174}
175
176func ExampleMkdirTemp_suffix() {
177	logsDir, err := os.MkdirTemp("", "*-logs")
178	if err != nil {
179		log.Fatal(err)
180	}
181	defer os.RemoveAll(logsDir) // clean up
182
183	// Logs can be cleaned out earlier if needed by searching
184	// for all directories whose suffix ends in *-logs.
185	globPattern := filepath.Join(os.TempDir(), "*-logs")
186	matches, err := filepath.Glob(globPattern)
187	if err != nil {
188		log.Fatalf("Failed to match %q: %v", globPattern, err)
189	}
190
191	for _, match := range matches {
192		if err := os.RemoveAll(match); err != nil {
193			log.Printf("Failed to remove %q: %v", match, err)
194		}
195	}
196}
197
198func ExampleCreateTemp() {
199	f, err := os.CreateTemp("", "example")
200	if err != nil {
201		log.Fatal(err)
202	}
203	defer os.Remove(f.Name()) // clean up
204
205	if _, err := f.Write([]byte("content")); err != nil {
206		log.Fatal(err)
207	}
208	if err := f.Close(); err != nil {
209		log.Fatal(err)
210	}
211}
212
213func ExampleCreateTemp_suffix() {
214	f, err := os.CreateTemp("", "example.*.txt")
215	if err != nil {
216		log.Fatal(err)
217	}
218	defer os.Remove(f.Name()) // clean up
219
220	if _, err := f.Write([]byte("content")); err != nil {
221		f.Close()
222		log.Fatal(err)
223	}
224	if err := f.Close(); err != nil {
225		log.Fatal(err)
226	}
227}
228
229func ExampleReadFile() {
230	data, err := os.ReadFile("testdata/hello")
231	if err != nil {
232		log.Fatal(err)
233	}
234	os.Stdout.Write(data)
235
236	// Output:
237	// Hello, Gophers!
238}
239
240func ExampleWriteFile() {
241	err := os.WriteFile("testdata/hello", []byte("Hello, Gophers!"), 0666)
242	if err != nil {
243		log.Fatal(err)
244	}
245}
246
247func ExampleMkdir() {
248	err := os.Mkdir("testdir", 0750)
249	if err != nil && !os.IsExist(err) {
250		log.Fatal(err)
251	}
252	err = os.WriteFile("testdir/testfile.txt", []byte("Hello, Gophers!"), 0660)
253	if err != nil {
254		log.Fatal(err)
255	}
256}
257
258func ExampleMkdirAll() {
259	err := os.MkdirAll("test/subdir", 0750)
260	if err != nil {
261		log.Fatal(err)
262	}
263	err = os.WriteFile("test/subdir/testfile.txt", []byte("Hello, Gophers!"), 0660)
264	if err != nil {
265		log.Fatal(err)
266	}
267}
268
269func ExampleReadlink() {
270	// First, we create a relative symlink to a file.
271	d, err := os.MkdirTemp("", "")
272	if err != nil {
273		log.Fatal(err)
274	}
275	defer os.RemoveAll(d)
276	targetPath := filepath.Join(d, "hello.txt")
277	if err := os.WriteFile(targetPath, []byte("Hello, Gophers!"), 0644); err != nil {
278		log.Fatal(err)
279	}
280	linkPath := filepath.Join(d, "hello.link")
281	if err := os.Symlink("hello.txt", filepath.Join(d, "hello.link")); err != nil {
282		if errors.Is(err, errors.ErrUnsupported) {
283			// Allow the example to run on platforms that do not support symbolic links.
284			fmt.Printf("%s links to %s\n", filepath.Base(linkPath), "hello.txt")
285			return
286		}
287		log.Fatal(err)
288	}
289
290	// Readlink returns the relative path as passed to os.Symlink.
291	dst, err := os.Readlink(linkPath)
292	if err != nil {
293		log.Fatal(err)
294	}
295	fmt.Printf("%s links to %s\n", filepath.Base(linkPath), dst)
296
297	var dstAbs string
298	if filepath.IsAbs(dst) {
299		dstAbs = dst
300	} else {
301		// Symlink targets are relative to the directory containing the link.
302		dstAbs = filepath.Join(filepath.Dir(linkPath), dst)
303	}
304
305	// Check that the target is correct by comparing it with os.Stat
306	// on the original target path.
307	dstInfo, err := os.Stat(dstAbs)
308	if err != nil {
309		log.Fatal(err)
310	}
311	targetInfo, err := os.Stat(targetPath)
312	if err != nil {
313		log.Fatal(err)
314	}
315	if !os.SameFile(dstInfo, targetInfo) {
316		log.Fatalf("link destination (%s) is not the same file as %s", dstAbs, targetPath)
317	}
318
319	// Output:
320	// hello.link links to hello.txt
321}
322
323func ExampleUserCacheDir() {
324	dir, dirErr := os.UserCacheDir()
325	if dirErr == nil {
326		dir = filepath.Join(dir, "ExampleUserCacheDir")
327	}
328
329	getCache := func(name string) ([]byte, error) {
330		if dirErr != nil {
331			return nil, &os.PathError{Op: "getCache", Path: name, Err: os.ErrNotExist}
332		}
333		return os.ReadFile(filepath.Join(dir, name))
334	}
335
336	var mkdirOnce sync.Once
337	putCache := func(name string, b []byte) error {
338		if dirErr != nil {
339			return &os.PathError{Op: "putCache", Path: name, Err: dirErr}
340		}
341		mkdirOnce.Do(func() {
342			if err := os.MkdirAll(dir, 0700); err != nil {
343				log.Printf("can't create user cache dir: %v", err)
344			}
345		})
346		return os.WriteFile(filepath.Join(dir, name), b, 0600)
347	}
348
349	// Read and store cached data.
350	// …
351	_ = getCache
352	_ = putCache
353
354	// Output:
355}
356
357func ExampleUserConfigDir() {
358	dir, dirErr := os.UserConfigDir()
359
360	var (
361		configPath string
362		origConfig []byte
363	)
364	if dirErr == nil {
365		configPath = filepath.Join(dir, "ExampleUserConfigDir", "example.conf")
366		var err error
367		origConfig, err = os.ReadFile(configPath)
368		if err != nil && !os.IsNotExist(err) {
369			// The user has a config file but we couldn't read it.
370			// Report the error instead of ignoring their configuration.
371			log.Fatal(err)
372		}
373	}
374
375	// Use and perhaps make changes to the config.
376	config := bytes.Clone(origConfig)
377	// …
378
379	// Save changes.
380	if !bytes.Equal(config, origConfig) {
381		if configPath == "" {
382			log.Printf("not saving config changes: %v", dirErr)
383		} else {
384			err := os.MkdirAll(filepath.Dir(configPath), 0700)
385			if err == nil {
386				err = os.WriteFile(configPath, config, 0600)
387			}
388			if err != nil {
389				log.Printf("error saving config changes: %v", err)
390			}
391		}
392	}
393
394	// Output:
395}
396