just playing with tangled
1// Copyright 2022 The Jujutsu Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::io::Write as _;
16
17use crate::common::TestEnvironment;
18
19#[test]
20fn test_sparse_manage_patterns() {
21 let mut test_env = TestEnvironment::default();
22 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
23 let repo_path = test_env.env_root().join("repo");
24
25 let edit_script = test_env.set_up_fake_editor();
26
27 // Write some files to the working copy
28 std::fs::write(repo_path.join("file1"), "contents").unwrap();
29 std::fs::write(repo_path.join("file2"), "contents").unwrap();
30 std::fs::write(repo_path.join("file3"), "contents").unwrap();
31
32 // By default, all files are tracked
33 let output = test_env.run_jj_in(&repo_path, ["sparse", "list"]);
34 insta::assert_snapshot!(output, @r"
35 .
36 [EOF]
37 ");
38
39 // Can stop tracking all files
40 let output = test_env.run_jj_in(&repo_path, ["sparse", "set", "--remove", "."]);
41 insta::assert_snapshot!(output, @r"
42 ------- stderr -------
43 Added 0 files, modified 0 files, removed 3 files
44 [EOF]
45 ");
46 // The list is now empty
47 let output = test_env.run_jj_in(&repo_path, ["sparse", "list"]);
48 insta::assert_snapshot!(output, @"");
49 // They're removed from the working copy
50 assert!(!repo_path.join("file1").exists());
51 assert!(!repo_path.join("file2").exists());
52 assert!(!repo_path.join("file3").exists());
53 // But they're still in the commit
54 let output = test_env.run_jj_in(&repo_path, ["file", "list"]);
55 insta::assert_snapshot!(output, @r"
56 file1
57 file2
58 file3
59 [EOF]
60 ");
61
62 // Run commands in sub directory to ensure that patterns are parsed as
63 // workspace-relative paths, not cwd-relative ones.
64 let sub_dir = repo_path.join("sub");
65 std::fs::create_dir(&sub_dir).unwrap();
66
67 // Not a workspace-relative path
68 let output = test_env.run_jj_in(&sub_dir, ["sparse", "set", "--add=../file2"]);
69 insta::assert_snapshot!(output, @r#"
70 ------- stderr -------
71 error: invalid value '../file2' for '--add <ADD>': Invalid component ".." in repo-relative path "../file2"
72
73 For more information, try '--help'.
74 [EOF]
75 [exit status: 2]
76 "#);
77
78 // Can `--add` a few files
79 let output = test_env.run_jj_in(
80 &sub_dir,
81 ["sparse", "set", "--add", "file2", "--add", "file3"],
82 );
83 insta::assert_snapshot!(output, @r"
84 ------- stderr -------
85 Added 2 files, modified 0 files, removed 0 files
86 [EOF]
87 ");
88 let output = test_env.run_jj_in(&sub_dir, ["sparse", "list"]);
89 insta::assert_snapshot!(output, @r"
90 file2
91 file3
92 [EOF]
93 ");
94 assert!(!repo_path.join("file1").exists());
95 assert!(repo_path.join("file2").exists());
96 assert!(repo_path.join("file3").exists());
97
98 // Can combine `--add` and `--remove`
99 let output = test_env.run_jj_in(
100 &sub_dir,
101 [
102 "sparse", "set", "--add", "file1", "--remove", "file2", "--remove", "file3",
103 ],
104 );
105 insta::assert_snapshot!(output, @r"
106 ------- stderr -------
107 Added 1 files, modified 0 files, removed 2 files
108 [EOF]
109 ");
110 let output = test_env.run_jj_in(&sub_dir, ["sparse", "list"]);
111 insta::assert_snapshot!(output, @r"
112 file1
113 [EOF]
114 ");
115 assert!(repo_path.join("file1").exists());
116 assert!(!repo_path.join("file2").exists());
117 assert!(!repo_path.join("file3").exists());
118
119 // Can use `--clear` and `--add`
120 let output = test_env.run_jj_in(&sub_dir, ["sparse", "set", "--clear", "--add", "file2"]);
121 insta::assert_snapshot!(output, @r"
122 ------- stderr -------
123 Added 1 files, modified 0 files, removed 1 files
124 [EOF]
125 ");
126 let output = test_env.run_jj_in(&sub_dir, ["sparse", "list"]);
127 insta::assert_snapshot!(output, @r"
128 file2
129 [EOF]
130 ");
131 assert!(!repo_path.join("file1").exists());
132 assert!(repo_path.join("file2").exists());
133 assert!(!repo_path.join("file3").exists());
134
135 // Can reset back to all files
136 let output = test_env.run_jj_in(&sub_dir, ["sparse", "reset"]);
137 insta::assert_snapshot!(output, @r"
138 ------- stderr -------
139 Added 2 files, modified 0 files, removed 0 files
140 [EOF]
141 ");
142 let output = test_env.run_jj_in(&sub_dir, ["sparse", "list"]);
143 insta::assert_snapshot!(output, @r"
144 .
145 [EOF]
146 ");
147 assert!(repo_path.join("file1").exists());
148 assert!(repo_path.join("file2").exists());
149 assert!(repo_path.join("file3").exists());
150
151 // Can edit with editor
152 let edit_patterns = |patterns: &[&str]| {
153 let mut file = std::fs::File::create(&edit_script).unwrap();
154 file.write_all(b"dump patterns0\0write\n").unwrap();
155 for pattern in patterns {
156 file.write_all(pattern.as_bytes()).unwrap();
157 file.write_all(b"\n").unwrap();
158 }
159 };
160 let read_patterns = || std::fs::read_to_string(test_env.env_root().join("patterns0")).unwrap();
161
162 edit_patterns(&["file1"]);
163 let output = test_env.run_jj_in(&sub_dir, ["sparse", "edit"]);
164 insta::assert_snapshot!(output, @r"
165 ------- stderr -------
166 Added 0 files, modified 0 files, removed 2 files
167 [EOF]
168 ");
169 insta::assert_snapshot!(read_patterns(), @".");
170 let output = test_env.run_jj_in(&sub_dir, ["sparse", "list"]);
171 insta::assert_snapshot!(output, @r"
172 file1
173 [EOF]
174 ");
175
176 // Can edit with multiple files
177 edit_patterns(&["file3", "file2", "file3"]);
178 let output = test_env.run_jj_in(&sub_dir, ["sparse", "edit"]);
179 insta::assert_snapshot!(output, @r"
180 ------- stderr -------
181 Added 2 files, modified 0 files, removed 1 files
182 [EOF]
183 ");
184 insta::assert_snapshot!(read_patterns(), @"file1");
185 let output = test_env.run_jj_in(&sub_dir, ["sparse", "list"]);
186 insta::assert_snapshot!(output, @r"
187 file2
188 file3
189 [EOF]
190 ");
191}
192
193#[test]
194fn test_sparse_editor_avoids_unc() {
195 use std::path::PathBuf;
196
197 let mut test_env = TestEnvironment::default();
198 test_env.run_jj_in(".", ["git", "init", "repo"]).success();
199 let repo_path = test_env.env_root().join("repo");
200 let edit_script = test_env.set_up_fake_editor();
201
202 std::fs::write(edit_script, "dump-path path").unwrap();
203 test_env.run_jj_in(&repo_path, ["sparse", "edit"]).success();
204
205 let edited_path =
206 PathBuf::from(std::fs::read_to_string(test_env.env_root().join("path")).unwrap());
207 // While `assert!(!edited_path.starts_with("//?/"))` could work here in most
208 // cases, it fails when it is not safe to strip the prefix, such as paths
209 // over 260 chars.
210 assert_eq!(edited_path, dunce::simplified(&edited_path));
211}