##// END OF EJS Templates
java/org/implab/gradle/Utils rmoved to org/implab/gradle/mercurial/Utils to resolve conflicts with other plugins
cin -
r4:645e2e6a0875 v1.0.1 default
parent child
Show More
@@ -1,2 +1,2
1 1 group=org.implab.gradle
2 version=1.0.0 No newline at end of file
2 version=1.0.1 No newline at end of file
@@ -1,172 +1,171
1 1 package org.implab.gradle.mercurial;
2 2
3 3 import java.nio.charset.Charset;
4 4 import java.util.ArrayList;
5 5 import java.util.Collections;
6 6 import java.util.List;
7 7 import java.util.Objects;
8 8 import java.util.Optional;
9 9 import java.util.function.Function;
10 10 import java.util.regex.Matcher;
11 11 import java.util.regex.Pattern;
12 12
13 13 import org.gradle.api.Project;
14 import org.implab.gradle.Utils;
15 14
16 15 import groovy.lang.Closure;
17 16
18 17 public class MercurialExtension {
19 18 private static final String COMMIT_INFO_TEMPLATE = "{latesttag('re:^v') % '{ifeq(tag,'null','',tag)}:{distance}'}:{branch}:{node|short}";
20 19
21 20 private static final Pattern versionPattern = Pattern.compile("^(?:v[\\-_\\.]?)?(.*)");
22 21
23 22 private final Project project;
24 23
25 24 private Charset outputCharset = Charset.defaultCharset();
26 25
27 26 private WorkspaceInfo workspaceInfo;
28 27
29 28 private String hgCmd = "hg";
30 29
31 30 private String stagingBookmark = "staging";
32 31
33 32 private String releaseBookmark = "prod";
34 33
35 34 private SemVersion defaultWorkspaceVersion = new SemVersion(0, 0, 1, "dev", null);
36 35
37 36 private Function<SemVersion, SemVersion> preReleasePolicy;
38 37
39 38 public MercurialExtension(Project project) {
40 39 Objects.requireNonNull(project);
41 40
42 41 this.project = project;
43 42 }
44 43
45 44 public String hg(String... args) {
46 45 List<String> commandLine = new ArrayList<>();
47 46 commandLine.add(hgCmd);
48 47 Collections.addAll(commandLine, args);
49 48
50 49 return Utils.execCmd(commandLine, outputCharset.name());
51 50 }
52 51
53 52 public String getReleaseBookmark() {
54 53 return releaseBookmark;
55 54 }
56 55
57 56 public void setReleaseBookmark(String value) {
58 57 if(value == null)
59 58 throw new IllegalArgumentException();
60 59 releaseBookmark = value;
61 60 }
62 61
63 62 public String getStagingBookmark() {
64 63 return stagingBookmark;
65 64 }
66 65
67 66 public void setStagingBookmark(String value) {
68 67 if(value == null)
69 68 throw new IllegalArgumentException();
70 69 stagingBookmark = value;
71 70 }
72 71
73 72 public Charset getOutputCharset() {
74 73 return outputCharset;
75 74 }
76 75
77 76 public void setOutputCharset(Charset outputCharset) {
78 77 this.outputCharset = Optional.ofNullable(outputCharset).orElseGet(Charset::defaultCharset);
79 78 }
80 79
81 80 public void setOutputCharset(String outputCharset) {
82 81 this.outputCharset = Optional.ofNullable(outputCharset).map(x -> Charset.forName(x))
83 82 .orElseGet(Charset::defaultCharset);
84 83 }
85 84
86 85 public String getHgCmd() {
87 86 return hgCmd;
88 87 }
89 88
90 89 public void setHgCmd(String hgCmd) {
91 90 this.hgCmd = hgCmd;
92 91 }
93 92
94 93 public WorkspaceInfo getWorkspaceInfo() {
95 94 if (workspaceInfo == null)
96 95 workspaceInfo = loadWorkspaceInfo();
97 96 return workspaceInfo;
98 97 }
99 98
100 99 public SemVersion getWorkspaceVersion() {
101 100 return tryParseVersion(getWorkspaceInfo().getVersionTag()).orElse(defaultWorkspaceVersion);
102 101 }
103 102
104 103 private SemVersion defaultPreReleasePolicy(SemVersion version) {
105 104 String changeset = getWorkspaceInfo().getChangeset();
106 105 return version.addPatch(1).withPreRelease("snapshot").withMeta(changeset);
107 106 }
108 107
109 108 public void preReleasePolicy(Closure<SemVersion> policy) {
110 109 if (policy == null)
111 110 throw new IllegalArgumentException();
112 111
113 112 this.preReleasePolicy = x -> {
114 113 policy.setDelegate(getWorkspaceInfo());
115 114 policy.setResolveStrategy(Closure.DELEGATE_FIRST);
116 115 return policy.call(x);
117 116 };
118 117 }
119 118
120 119 public void preReleasePolicy(Function<SemVersion, SemVersion> policy) {
121 120 if (policy == null)
122 121 throw new IllegalArgumentException();
123 122 this.preReleasePolicy = policy;
124 123 }
125 124
126 125 public void applyVersioningPolicy() {
127 126 Object version = project.getVersion();
128 127 if (version == null || version.toString().isBlank()
129 128 || version.toString().equalsIgnoreCase(Project.DEFAULT_VERSION)) {
130 129 // if the version isn't specified
131 130 int distance = getWorkspaceInfo().getVersionDistance();
132 131
133 132 // the current workspace is not tagged with the version
134 133 if (distance > 0) {
135 134 SemVersion preReleaseVersion = Optional.ofNullable(preReleasePolicy)
136 135 .orElse(this::defaultPreReleasePolicy)
137 136 .apply(getWorkspaceVersion());
138 137
139 138 project.setVersion(preReleaseVersion);
140 139 } else {
141 140 project.setVersion(getWorkspaceVersion());
142 141 }
143 142 } else {
144 143 project.setVersion(SemVersion.toSemVersion(version, false));
145 144 }
146 145 }
147 146
148 147 String[] queryLogInfo() {
149 148 return hg("log", "-r", ".", "--template", COMMIT_INFO_TEMPLATE).split(":");
150 149 }
151 150
152 151 WorkspaceInfo loadWorkspaceInfo() {
153 152 boolean isDirty = checkIsDirty();
154 153 String[] info = queryLogInfo();
155 154 return new WorkspaceInfo(info[0], Integer.parseInt(info[1]), info[2], info[3], isDirty);
156 155 }
157 156
158 157 boolean checkIsDirty() {
159 158 return !hg("status", "-mard").isBlank();
160 159 }
161 160
162 161 Optional<SemVersion> tryParseVersion(String version) {
163 162 if (version == null)
164 163 return Optional.empty();
165 164
166 165 Matcher m = versionPattern.matcher(version);
167 166 boolean isMatch = m.matches();
168 167
169 168 return isMatch ? SemVersion.tryParseLax(m.group(1)) : Optional.empty();
170 169 }
171 170
172 171 }
@@ -1,114 +1,114
1 package org.implab.gradle;
1 package org.implab.gradle.mercurial;
2 2
3 3 import java.io.ByteArrayOutputStream;
4 4 import java.io.Closeable;
5 5 import java.io.File;
6 6 import java.io.FileOutputStream;
7 7 import java.io.IOException;
8 8 import java.io.InputStream;
9 9 import java.io.OutputStream;
10 10 import java.util.List;
11 11 import java.util.Scanner;
12 12
13 13 import org.gradle.api.Action;
14 14 import groovy.json.JsonGenerator;
15 15 import groovy.json.JsonOutput;
16 16 import groovy.json.JsonGenerator.Converter;
17 17 import groovy.lang.Closure;
18 18
19 19 public final class Utils {
20 20 public static void redirectIO(final InputStream src, final Action<String> consumer) {
21 21 new Thread(() -> {
22 22 try (Scanner sc = new Scanner(src)) {
23 23 while (sc.hasNextLine()) {
24 24 consumer.execute(sc.nextLine());
25 25 }
26 26 }
27 27 }).start();
28 28 }
29 29
30 30 public static String execCmd(List<String> args, String charset) {
31 31 if (args == null || args.size() == 0)
32 32 throw new IllegalArgumentException();
33 33
34 34 ProcessBuilder builder = new ProcessBuilder(args);
35 35
36 36 Process p;
37 37 try {
38 38 p = builder.start();
39 39
40 40 String output = readAll(p.getInputStream(), charset);
41 41
42 42 int code = p.waitFor();
43 43 if (code != 0)
44 44 throw new RuntimeException(String.format("The process `%s` failed with code: %s", args.get(0), code));
45 45
46 46 return output;
47 47 } catch (IOException | InterruptedException e) {
48 48 throw new RuntimeException(String.format("Failed to execute `%s`", args.get(0)), e);
49 49 }
50 50
51 51 }
52 52
53 53 public static void redirectIO(final InputStream src, final File file) {
54 54 new Thread(() -> {
55 55 try (OutputStream out = new FileOutputStream(file)) {
56 56 src.transferTo(out);
57 57 } catch (Exception e) {
58 58 // silence!
59 59 }
60 60 }).start();
61 61 }
62 62
63 63 public static String readAll(final InputStream src) throws IOException {
64 64 ByteArrayOutputStream out = new ByteArrayOutputStream();
65 65 src.transferTo(out);
66 66 return out.toString();
67 67 }
68 68
69 69 public static String readAll(final InputStream src, String charset) throws IOException {
70 70 ByteArrayOutputStream out = new ByteArrayOutputStream();
71 71 src.transferTo(out);
72 72 return out.toString(charset);
73 73 }
74 74
75 75 public static JsonGenerator createDefaultJsonGenerator() {
76 76 return new JsonGenerator.Options()
77 77 .excludeNulls()
78 78 .addConverter(new Converter() {
79 79 public boolean handles(Class<?> type) {
80 80 return (File.class == type);
81 81 }
82 82
83 83 public Object convert(Object value, String key) {
84 84 return ((File) value).getPath();
85 85 }
86 86 })
87 87 .build();
88 88 }
89 89
90 90 public static void closeSilent(Closeable handle) {
91 91 try {
92 92 handle.close();
93 93 } catch (Exception e) {
94 94 // silence!
95 95 }
96 96 }
97 97
98 98 public static String toJsonPretty(Object value) {
99 99 return JsonOutput.prettyPrint(createDefaultJsonGenerator().toJson(value));
100 100 }
101 101
102 102 public static boolean isNullOrEmptyString(String value) {
103 103 return (value == null || value.length() == 0);
104 104 }
105 105
106 106 public static <T> Action<T> wrapClosure(Closure<?> closure) {
107 107 return x -> {
108 108 closure.setDelegate(x);
109 109 closure.setResolveStrategy(Closure.DELEGATE_FIRST);
110 110 closure.call(x);
111 111 };
112 112 }
113 113
114 114 }
@@ -1,84 +1,84
1 1 package org.implab.gradle.mercurial.tasks;
2 2
3 3 import java.io.IOException;
4 4 import java.util.ArrayList;
5 5 import java.util.List;
6 6
7 7 import javax.inject.Inject;
8 8
9 9 import org.gradle.api.DefaultTask;
10 10 import org.gradle.api.model.ObjectFactory;
11 11 import org.gradle.api.provider.ListProperty;
12 12 import org.gradle.api.provider.Property;
13 13 import org.gradle.api.tasks.Internal;
14 14 import org.gradle.api.tasks.TaskAction;
15 import org.implab.gradle.Utils;
16 15 import org.implab.gradle.mercurial.MercurialExtension;
16 import org.implab.gradle.mercurial.Utils;
17 17
18 18 public class HgBookmark extends DefaultTask {
19 19
20 20 private final Property<String> cliCmd;
21 21
22 22 private final Property<Boolean> inactive;
23 23
24 24 private final Property<Boolean> force;
25 25
26 26 private final ListProperty<String> bookmarks;
27 27
28 28 private String commandOutput;
29 29
30 30 @Internal
31 31 protected MercurialExtension getMercurialExtension() {
32 32 return getProject().getExtensions().getByType(MercurialExtension.class);
33 33 }
34 34
35 35 @Inject
36 36 public HgBookmark(ObjectFactory factory) {
37 37 cliCmd = factory.property(String.class);
38 38 inactive = factory.property(Boolean.class);
39 39 force = factory.property(Boolean.class);
40 40 bookmarks = factory.listProperty(String.class);
41 41 cliCmd.convention(getMercurialExtension().getHgCmd());
42 42
43 43 onlyIf(t -> !getBookmarks().get().isEmpty());
44 44 }
45 45
46 46 @Internal
47 47 public Property<Boolean> getInactive() {
48 48 return inactive;
49 49 }
50 50
51 51 @Internal
52 52 public Property<Boolean> getForce() {
53 53 return force;
54 54 }
55 55
56 56 @Internal
57 57 public String getCommandOutput() {
58 58 return commandOutput;
59 59 }
60 60
61 61 @Internal
62 62 public ListProperty<String> getBookmarks() {
63 63 return bookmarks;
64 64 }
65 65
66 66 @TaskAction
67 67 public void Run() throws IOException, InterruptedException, Exception {
68 68 List<String> commandLine = new ArrayList<>();
69 69
70 70 commandLine.add(cliCmd.get());
71 71 commandLine.add("bookmark");
72 72 if(inactive.isPresent())
73 73 commandLine.add("-i");
74 74 if(force.isPresent())
75 75 commandLine.add("-f");
76 76
77 77 commandLine.addAll(bookmarks.get());
78 78
79 79 getLogger().info("Starting: {}", commandLine);
80 80
81 81 commandOutput = Utils.execCmd(commandLine, getMercurialExtension().getOutputCharset().name());
82 82 }
83 83
84 84 }
@@ -1,76 +1,76
1 1 package org.implab.gradle.mercurial.tasks;
2 2
3 3 import java.io.IOException;
4 4 import java.util.ArrayList;
5 5 import java.util.List;
6 6
7 7 import javax.inject.Inject;
8 8
9 9 import org.gradle.api.DefaultTask;
10 10 import org.gradle.api.model.ObjectFactory;
11 11 import org.gradle.api.provider.ListProperty;
12 12 import org.gradle.api.provider.Property;
13 13 import org.gradle.api.tasks.Internal;
14 14 import org.gradle.api.tasks.TaskAction;
15 import org.implab.gradle.Utils;
16 15 import org.implab.gradle.mercurial.MercurialExtension;
16 import org.implab.gradle.mercurial.Utils;
17 17
18 18 public class HgTag extends DefaultTask {
19 19
20 20 private final Property<String> cliCmd;
21 21
22 22 private final Property<Boolean> force;
23 23
24 24 private final ListProperty<String> tags;
25 25
26 26 private String commandOutput;
27 27
28 28 @Internal
29 29 protected MercurialExtension getMercurialExtension() {
30 30 return getProject().getExtensions().getByType(MercurialExtension.class);
31 31 }
32 32
33 33 @Inject
34 34 public HgTag(ObjectFactory factory) {
35 35 cliCmd = factory.property(String.class);
36 36 force = factory.property(Boolean.class);
37 37 tags = factory.listProperty(String.class);
38 38 cliCmd.convention(getMercurialExtension().getHgCmd());
39 39
40 40 onlyIf(t -> !getTags().get().isEmpty());
41 41 }
42 42
43 43 @Internal
44 44 public Property<Boolean> getForce() {
45 45 return force;
46 46 }
47 47
48 48 @Internal
49 49 public String getCommandOutput() {
50 50 return commandOutput;
51 51 }
52 52
53 53 @Internal
54 54 public ListProperty<String> getTags() {
55 55 return tags;
56 56 }
57 57
58 58 @TaskAction
59 59 public void Run() throws IOException, InterruptedException, Exception {
60 60 List<String> commandLine = new ArrayList<>();
61 61
62 62 commandLine.add(cliCmd.get());
63 63
64 64 commandLine.add("tag");
65 65
66 66 if(force.isPresent())
67 67 commandLine.add("-f");
68 68
69 69 commandLine.addAll(tags.get());
70 70
71 71 getLogger().info("Starting: {}", commandLine);
72 72
73 73 commandOutput = Utils.execCmd(commandLine, getMercurialExtension().getOutputCharset().name());
74 74 }
75 75
76 76 }
@@ -1,70 +1,70
1 1 package org.implab.gradle.mercurial.tasks;
2 2
3 3 import java.io.IOException;
4 4 import java.util.ArrayList;
5 5 import java.util.List;
6 6
7 7 import org.gradle.api.DefaultTask;
8 8 import org.gradle.api.provider.Property;
9 9 import org.gradle.api.provider.Provider;
10 10 import org.gradle.api.tasks.Internal;
11 11 import org.gradle.api.tasks.TaskAction;
12 import org.implab.gradle.Utils;
13 12 import org.implab.gradle.mercurial.MercurialExtension;
13 import org.implab.gradle.mercurial.Utils;
14 14
15 15 public class HgTask extends DefaultTask {
16 16
17 17 private final Property<String> cliCmd;
18 18
19 19 private List<Provider<String>> commandArgs;
20 20
21 21 private String commandOutput;
22 22
23 23 @Internal
24 24 protected MercurialExtension getMercurialExtension() {
25 25 return getProject().getExtensions().getByType(MercurialExtension.class);
26 26 }
27 27
28 28 public HgTask() {
29 29 cliCmd = getProject().getObjects().property(String.class);
30 30 cliCmd.convention(getMercurialExtension().getHgCmd());
31 31
32 32 }
33 33
34 34 @Internal
35 35 public String getCommandOutput() {
36 36 return commandOutput;
37 37 }
38 38
39 39 public void clearCommandArgs() {
40 40 commandArgs.clear();
41 41 }
42 42
43 43 public void commandArgs(Object... args) {
44 44 for (Object arg : args) {
45 45 if (arg == null)
46 46 continue;
47 47 if (arg instanceof Provider<?>)
48 48 commandArgs.add(((Provider<?>) arg).map(x -> x.toString()));
49 49 else
50 50 commandArgs.add(getProject().getProviders().provider(() -> arg.toString()));
51 51 }
52 52 }
53 53
54 54 @TaskAction
55 55 public void Run() throws IOException, InterruptedException, Exception {
56 56 List<String> commandLine = new ArrayList<>();
57 57
58 58 commandLine.add(cliCmd.get());
59 59
60 60 for (Provider<String> arg : commandArgs) {
61 61 if (arg.isPresent())
62 62 commandLine.add(arg.get());
63 63 }
64 64
65 65 getLogger().info("Starting: ", commandLine);
66 66
67 67 commandOutput = Utils.execCmd(commandLine, getMercurialExtension().getOutputCharset().name());
68 68 }
69 69
70 70 }
@@ -1,120 +1,120
1 1 # Mercurial build integration
2 2
3 3 ## SYNOPSIS
4 4
5 5 ```groovy
6 6
7 7 plugins {
8 id 'org.implab.gradle-mercurial' version '1.0.0' // or specify latest version
8 id 'org.implab.gradle-mercurial' version '1.0.1' // specify the latest version
9 9 }
10 10
11 11 mercurial {
12 12 releaseBookmark = 'prod'
13 13
14 14 preReleasePolicy { it
15 15 // this is the default behaviour
16 16 .addPatch(1)
17 17 .withPreRelease('snapshot')
18 .withMeta('changeset')
18 .withMeta(changeset)
19 19 }
20 20
21 21 // get version from repository and apply it to the project
22 22 applyVersioningPolicy()
23 23 }
24 24
25 25 ```
26 26
27 27 ## DESCRIPTION
28 28
29 29 ### `semver(versionString)`
30 30
31 31 Parses the specified version string and returns the semantic version object
32 32
33 33 ### `mercurial(Closure configure)`
34 34
35 35 The extension added by the plugin to the project. Apply this plugin to the
36 36 root project and use the `mercurial { ... }` section to configure the
37 37 versioning.
38 38
39 39 See the description below for more details about settings.
40 40
41 41 #### `hgCmd`
42 42
43 43 The command which will be executed to perform the mercurial commands.
44 44 The default value is `hg`.
45 45
46 46 #### `outputCharset`
47 47
48 48 The charset for the `hgCmd` output, this property defaults
49 49 to the default charset of the operating system.
50 50
51 51 #### `hg(...args)`
52 52
53 53 Executes the mercurial command, returns the command output as text.
54 54
55 55 #### `workspaceInfo` (read-only)
56 56
57 57 Returns the information about current workspace, see description
58 58 below for details.
59 59
60 60 #### `workspaceVersion`
61 61
62 62 Returns the semantic version obtained from the repository. Querying
63 63 this property will lead querying the workspace info.
64 64
65 65 #### `applyVersioningPolicy()`
66 66
67 67 Reads the workspace information and sets the version of the project
68 68 according to settings.
69 69
70 70 If the version was specified using properties, then the specified
71 71 version will take preceding over the calculated one.
72 72
73 73 #### `preReleasePolicy(Closure<SemVersion> config)`
74 74
75 75 The closure which is used to calculate the version of the project
76 76 when the current commit isn't marked with a version tag.
77 77
78 78 The default behaviour is to increment the patch version and
79 79 to set the pre-release suffix to `'snapshot'`.
80 80
81 81 ### `WorkspaceInfo`
82 82
83 83 This class encapsulates information about the current workspace.
84 84 All properties are read-only.
85 85
86 86 #### `versionTag`
87 87
88 88 The original version tag from the repository before parsing.
89 89
90 90 #### `changeSet`
91 91
92 92 The changeset id of the current workspace.
93 93
94 94 #### `versionDistance`
95 95
96 96 The distance in commits to the versionTag
97 97
98 98 #### `branch`
99 99
100 100 The name of the current sources branch.
101 101
102 102 #### `isDirty`
103 103
104 104 This flag indicates uncommited changes to the workspace. This flag is useful
105 105 to control some pipelines which run locally on developer machines.
106 106
107 107 ## TASKS
108 108
109 109 ### `release`
110 110
111 111 Marks this commit with current version and pre-release suffix removed and
112 112 moves the `release` bookmark to it.
113 113
114 114 ### `staging`
115 115
116 116 Marks this commit with current version and moves the `staging` bookmark to it.
117 117
118 118 ### `printVersion`
119 119
120 120 Prints the current version.
General Comments 0
You need to be logged in to leave comments. Login now