Since my Jenkinsfile has almost 2000 lines of code(Scripted pipelines) it is obvious that it is better to refactor it to use shared libraries. The thing that stops me from that - is the way i have to import this libraries in the Jenkinsfile. Either using the #Library notation to import the global configured library or using library step to load library dynamically i loose code completion and possibility to CTRL+click the method\class\variable.
Am i missing something? How do you solve this issue? It is very frustrating to return 20 years back to search manually for some method through all code base instead of simply clicking it in the IDE to find it's implementation.
there are several things that you can do.
First of all if your libraries have .groovy extension then use class inside, for example:
class NotificationLib() {
}
then, here in your Lib class add the methods you are interested.
next step will be (all this assume that your pipeline and libraries are in same repository) to use #Library in pipeline, but also us import or new for the classes of your libraries
most probably you will need to have constructors in your Lib classes but that's fine.
Hope it helped.
Related
Xcode 11 is recompiling (nearly?) my whole project, even if I just change a local private variable, or change a value of a constant in local scope, sometimes even in local private function scope. I sometime can get 2 or 3 changes with quick builds as expected, but soon enough it decides to recompile everything again (which takes too long).
Any ideas what might be going on? Is Xcode not able to determine what's changed, why does it recompile so much other stuff (even other modules).
Any advice is highly appreciated, thanks!
We had the same problem and we fixed it. Twice.
Incremental build (same build machine):
before: ~10m
after: ~35s
HOW?
Let's start with our experience first. We had a massive Swift/Obj-C project and that was the main concern: build times were slow and you had to create a new project to implement a new feature (literally). Bonus points for never-working syntax highlighting.
Theory
To truly fix this you have to truly understand how build system works.
For example, let's try this code snippet:
import FacebookSDK
import RxSwift
import PinLayout
and imagine you use all of these imports in your file. And also this file depends on another file, which depends on another libraries, which in turn uses another libraries etc.
So to compile your file Xcode has to compile every library you mentioned and every file it depends on, so if you change one of the "core" files Xcode has to rebuild literally whole project.
Xcode build is multi-threaded, but it consists of many single-threaded trees.
So on the first step of every incremental build Xcode is deciding which files have to be re-compiled and builds an AST tree. If you change a file which is acting as "dependable" on other files, so every other file which acts as "dependent" has to be recompiled.
So the first advice is to lower coupling. Your project parts have to be independent of each other.
Obj-C/Swift bridge
Problem with those trees if you're using a Obj-C/Swift bridge, Xcode has to go through more phases than usual:
Perfect world:
Builds Obj-C code
Build Swift code
Obj-C/Swift bridge:
[REPEATABLE STEP] Build Swift code, which is needed to compile Obj-C code
[REPEATABLE STEP] Build Obj-C code, which is needed to compile Swift code
Repeat 1 & 2 until you have only non-dependable Swift & Obj-C code left
Build Obj-C code
Build Swift code
So if you change something from step 1 or 2, you're basically in a trouble.
The best solution is to minimize Obj-C/Swift Bridge (and remove it from your project).
If you don't have an Obj-C/Swift Bridge, that's awesome and you're good to go to the next step:
Swift Package Manager
Time to move to SwiftPM (or at least configure your Cocoapods better).
Thing is, most frameworks with default Cocoapods configuration drag along with themselves a lot of stuff you don't need.
To test this create an empty project with only one dependency like PinLayout, for example and try to write this code with Cocoapods (default configuration) and SwiftPM.
import PinLayout
final class TestViewController: UIViewController {
}
Spoiler: Cocoapods will compile this code, because Cocoapods will import EVERY IMPORT of PinLayout (including UIKit) and SwiftPM will not because SwiftPM imports frameworks atomically.
Dirty hack
Do you remember Xcode build is multi-threaded?
Well, you can abuse it, if you are able to split your project to many independent pieces and import all of them as independent frameworks to your project. It does lower the coupling and that was actually the first solution we used, but it wasn't in fact very effective, because we could only reduce incremental build time to ~4-5m which is NOTHING compared to the first method.
There's no golden bullet here, but plenty of things to check:
Make sure you're actually using the Debug configuration in your scheme
See below for how to ensure you're using incremental builds versus whole module per matt's advice. Also make sure your Optimization Level for Debug builds is none.
If you're using type-inference heavy frameworks like RxSwift, adding explicit type annotations can speed up build times.
If the project is very big, you could consider refactoring out logical groups of source files into frameworks, but that may be too drastic of a change than you'd prefer
It might help if you provided some more specifics about the project: are you statically linking any libraries? Is it a framework or app target? How big and what swift version are you using? Do you have any custom Build Phases like linters or code generation that could be skipped sometimes?
We are using a Jenkins Shared Library to centralize some code for all our (scripted) pipelines. Now we factored out some Groovy code into a .jar library (written in Kotlin, compiled to be Java 8 compatible). We published this library to our in-house maven repo and now want to use it in our Shared Libary.
We are using #Grab to load our library and up until that point it works like a charm. However we are getting NoSuchMethodError's. We pinpointed it down a bit, we are using OkHttp in our Kotlin lib. OkHttp internally uses Okio. When we call methods that internally call OkHttp-Code from our pipeline, everything is fine. However when the OkHttp-Code call Okio internally, we get a NoSuchMethodError.
We already checked the published .jar file, it contains the classes with the methods that seem to be missing. Does anybody have an idea what the issue could be?
While we are at it, we can't access environment variables set on Jenkins in our Kotlin library, is there a way we can fix this?
We figured it out. The problem was, that a Jenkins plugin used an older version of okio internally. Because plugins and shared libraries somehow share the same classpath, okio did not get loaded and the version from the plugin got used, therefore the class was not present.
We fixed this by repackaging all dependencies in our .jar, so package names would not interfere and we can make sure that our specified dependencies are being used.
Looking the dependencies here you have a few problems:
OKHttp - seems to expect some Android libraries
okio - depends on the Kotlin runtime
Any calls to these will result in method not found errors unless you find a way to make them available without causing problems in Jenkins
I do not completely understand the difference between part/part of and import/export when using libraries in Dart. For example:
one.dart:
library one;
part "two.dart";
Class One {
};
and
two.dart:
part of one;
import 'somefile.dart';
Class Two {
}
versus
library one;
import 'two.dart';
Class One {
}
and
library two;
import 'somefile.dart';
export 'somefile.dart';
Class Two {
}
Both scenarios seem to do the same thing. When is it advantageous to use part and part of rather than import? And are there scenarios where import will not work, but part and part of will?
update 2018/03
part and part of is used more and more for code generation scenarios recently (instead of deprecated transformers) and unlikely to go away anytime soon.
Packages like built_value, json_serializable, and many others depend on it.
Discouraged is only the patter where all files of a package are tied together to a single library by having one library file and all other files being part of that library.
original
In Dart, private members are accessible within the same library. With import you import a library and can access only its public members. With part/part of you can split one library into several files and private members are accessible for all code within these files.
see clarifications to below paragraph in above update
Using part / part of is discouraged and the Dart team is considering getting rid of it. I assume they will introduce something like "friend" (https://github.com/dart-lang/sdk/issues/22841), where two libraries can access each other's private members as an alternative before they discontinue part / part of (maybe in a future Dart version).
Let's suppose we have a Dart library called mylib, whose file is lib/mylib.dart.
library mylib;
// Definitions
That library can be included in the main.dart file as
import 'package:mypackage/mylib.dart';
When you create a new library and use other libraries you want to make available automatically when using your package, then you use export:
library mylib;
export 'otherlib.dart';
// Definitions
You can use the show keyword to import/export only some parts of a library (like a class or something).
You are using the part of directive wrong here. You can't use both library and part of, which is used to specify the contents that belong to a library. For example, you can split your library file in more than one file (the parts):
Suppose we have in the file mylib.dart:
library mylib;
part 'src/class1.part';
// More parts
And then we have in another file src/class1.part the part specified in mylib.dart
part of mylib;
class Class1 {
/* ... */
}
The Creating Library Packages article on the dartlang.org site recommends avoiding part / part of.
Note: You may have heard of the part directive, which allows you to
split a library into multiple Dart files. We recommend that you avoid
using part and create mini libraries instead.
The 'mini libraries' referred to are small library dart files in src which are imported into and exported from main libraries.
using part/part of makes many files be treated as if they were one file
import/export doesn't, so this may be useful when private fields need to be accessed from another files (classes created on other files)
I'm building up some Dart code that I would like to use in an app where it is essentially a library to the javascript. I'm wondering how I can specify which Dart files I'd like in the project to be part of the library. For example, theres Foo.dart and Bar.dart. How can I have the created product include both Foo.dart and Bar.dart in one file? I'm also concerned about tree shaking since none of the classes are instantiated in Dart.
There's also a Baz.dart, and I would like to have a different build for compiling Foo.dart and Baz.dart into a single file (though this is less important, as I can accomplish this would separate projects and some symlinking).
Thanks!
This use case (build a JavaScript library with Dart) isn't supported yet.
The reworked js-interop package is supposed to allow to do that but I don't know about it's current state.
I'm building a program that uses Delphi Packages (BPLs) as plugins, but I'd like to use a custom extension to show that the files have a specific purpose instead of just being BPLs. That works well enough until I end up with one package having a dependency on another. Then the compiler automatically creates the binary with the extension BPL built in.
This wouldn't be too hard to fix with a hex editor, but that's sort of an extreme solution. Is there any way I could make the compiler generate the packages with the right dependency names in the first place?
EDIT: The answers so far seem to have not understood the question.
I know exactly how to create the packages with my custom TEP extension instead of a BPL extension. But if I have package1.TEP and package2.TEP, and package2 depends on package1, and then I try to load package2, it gives an error because it can't find "package1.BPL". What I want is to find some simpler way to make package2 look for the correct filename, "package1.TEP," that doesn't involve editing the binary after it's been created. Is there any way to do that?
Use the {$E} directive.
The simplest solution would be to use a post build event to rename your destination file from *.BPL to whatever specific extension you are requiring.
EDIT:
You could write a separate patch program to search for and patch the offending binaries and run it as part of the post build process. If a patch is made to the compiler, then you can remove your step easily.